<commit_before>'use strict';
/*
 * Simple BinaryWriter is a minimal tool to write binary stream with unpredictable size.
 * Useful for binary serialization.
 *
 * Copyright (c) 2016 Barbosik https://github.com/Barbosik
 * License: Apache License, Version 2.0
 */

function BinaryWriter() {
    this._buffer = parseInt(process.version[1]) < 6 ? new Buffer(1e5) : Buffer.allocUnsafe(1e5);
    this._length = 0;
}

module.exports = BinaryWriter;

BinaryWriter.prototype.writeUInt8 = function (value) {
    this._buffer.writeUInt8(value, this._length++, true);
};

BinaryWriter.prototype.writeUInt16 = function (value) {
    this._buffer.writeUInt16LE(value, this._length, true);
    this._length += 2;
};

BinaryWriter.prototype.writeUInt32 = function (value) {
    this._buffer.writeUInt32LE(value, this._length, true);
    this._length += 4;
};

BinaryWriter.prototype.writeFloat = function (value) {
    this._buffer.writeFloatLE(value, this._length, true);
    this._length += 4;
};

BinaryWriter.prototype.writeDouble = function (value) {
    this._buffer.writeDoubleLE(value, this._length, true);
    this._length += 8;
};

BinaryWriter.prototype.writeBytes = function (data) {
    data.copy(this._buffer, this._length, 0, data.length);
    this._length += data.length;
};

BinaryWriter.prototype.writeStringZeroUtf8 = function (value) {
    var length = Buffer.byteLength(value, 'utf8');
    this._buffer.write(value, this._length, 'utf8');
    this._length += length;
    this.writeUInt8(0);
};

BinaryWriter.prototype.writeStringZeroUnicode = function (value) {
    var length = Buffer.byteLength(value, 'ucs2');
    this._buffer.write(value, this._length, 'ucs2');
    this._length += length;
    this.writeUInt16(0);
};

BinaryWriter.prototype.toBuffer = function () {
    return Buffer.concat([this._buffer.slice(0, this._length)]);
};
<commit_msg>Update BinaryWriter.js<commit_after>'use strict';
/*
 * Simple BinaryWriter is a minimal tool to write binary stream with unpredictable size.
 * Useful for binary serialization.
 *
 * Copyright (c) 2016 Barbosik https://github.com/Barbosik
 * License: Apache License, Version 2.0
 */

const oldNode = parseInt(process.version[1]) < 6;
const allocMax = 1048576;

global.sharedBuffer = oldNode ? new Buffer(allocMax) : Buffer.allocUnsafe(allocMax);
global.allocLength = 0;

function BinaryWriter() {
    allocLength = 0;
}

module.exports = BinaryWriter;

BinaryWriter.prototype.writeUInt8 = function(value) {
    sharedBuffer.writeUInt8(value, allocLength++, true);
};

BinaryWriter.prototype.writeUInt16 = function(value) {
    sharedBuffer.writeUInt16LE(value, allocLength, true);
    allocLength += 2;
};

BinaryWriter.prototype.writeUInt32 = function(value) {
    sharedBuffer.writeUInt32LE(value, allocLength, true);
    allocLength += 4;
};

BinaryWriter.prototype.writeFloat = function(value) {
    sharedBuffer.writeFloatLE(value, allocLength, true);
    allocLength += 4;
};

BinaryWriter.prototype.writeDouble = function(value) {
    sharedBuffer.writeDoubleLE(value, allocLength, true);
    allocLength += 8;
};

BinaryWriter.prototype.writeBytes = function(data) {
    data.copy(sharedBuffer, allocLength, 0, data.length);
    allocLength += data.length;
};

BinaryWriter.prototype.writeStringZeroUtf8 = function(value) {
    var length = Buffer.byteLength(value, 'utf8');
    sharedBuffer.write(value, allocLength, 'utf8');
    allocLength += length;
    this.writeUInt8(0);
};

BinaryWriter.prototype.writeStringZeroUnicode = function(value) {
    var length = Buffer.byteLength(value, 'ucs2');
    sharedBuffer.write(value, allocLength, 'ucs2');
    allocLength += length;
    this.writeUInt16(0);
};

BinaryWriter.prototype.toBuffer = function() {
    var newBuf = oldNode ? new Buffer(allocLength) : Buffer.allocUnsafe(allocLength);
    sharedBuffer.copy(newBuf, 0, 0, allocLength);
    return newBuf;
};
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import {IntentLink} from 'part:@sanity/base/router'
import SanityPreview from 'part:@sanity/base/preview'
import QueryContainer from 'part:@sanity/base/query-container'
import Spinner from 'part:@sanity/components/loading/spinner'
import schema from 'part:@sanity/base/schema'
import Button from 'part:@sanity/components/buttons/default'
import {List, Item} from 'part:@sanity/components/lists/default'
import {intersection} from 'lodash'
import styles from './index.css'

const schemaTypeNames = schema.getTypeNames()

function stringifyArray(array) {
  return `["${array.join('","')}"]`
}

class DocumentList extends React.Component {
  static propTypes = {
    title: PropTypes.string,
    types: PropTypes.array,
    query: PropTypes.string,
    order: PropTypes.string,
    limit: PropTypes.number
  }

  static defaultProps = {
    title: 'Last created',
    order: '_createdAt desc',
    limit: 10,
    types: null,
    query: null
  }

  assembleQuery = () => {
    const {query, types, order, limit} = this.props

    if (query) {
      return query
    }

    const documentTypes = schemaTypeNames.filter(typeName => {
      const schemaType = schema.get(typeName)
      return schemaType.type && schemaType.type.name === 'document'
    })

    if (types) {
      return `
        *[
          _type in ${stringifyArray(intersection(types, documentTypes))}
        ] | order(${order}) [0...${limit}]`
    }

    return `
      *[
        _type in ${stringifyArray(documentTypes)}
      ] | {_id, _type} | order(${order}) [0...${limit}]`
  }

  render() {
    const {title, types} = this.props
    const query = this.assembleQuery()

    return (

{title}

        <List className={styles.list}>
          <QueryContainer query={query}>
            {({result, loading, error, onRetry}) => {
              if (loading) {
                return <Spinner center message="Loading items…" />
              }
              const items = result ? result.documents : []
              return items.map(item => {
                const type = schema.get(item._type)
                return (
                  <Item key={item._id}>
                    <IntentLink
                      intent="edit"
                      params={{
                        type: item._type,
                        id: item._id
                      }}
                      className={styles.link}
                    >
                      <SanityPreview layout="default" type={type} value={item} key={item._id} />
                    </IntentLink>
                  </Item>
                )
              })
            }}
          </QueryContainer>
        </List>

          <Button bleed color="primary" kind="simple">
            {types && types.length === 1 ? `Create new ${types[0]}` : 'Create new document'}
          </Button>

    )
  }
}

export default {
  name: 'document-list',
  component: DocumentList
}
<commit_msg>[dashboard] Only show the IntentButton for one type<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import {IntentLink} from 'part:@sanity/base/router'
import SanityPreview from 'part:@sanity/base/preview'
import QueryContainer from 'part:@sanity/base/query-container'
import Spinner from 'part:@sanity/components/loading/spinner'
import schema from 'part:@sanity/base/schema'
import IntentButton from 'part:@sanity/components/buttons/intent'
import {List, Item} from 'part:@sanity/components/lists/default'
import {intersection} from 'lodash'
import styles from './index.css'

const schemaTypeNames = schema.getTypeNames()

function stringifyArray(array) {
  return `["${array.join('","')}"]`
}

class DocumentList extends React.Component {
  static propTypes = {
    title: PropTypes.string,
    types: PropTypes.array,
    query: PropTypes.string,
    order: PropTypes.string,
    limit: PropTypes.number
  }

  static defaultProps = {
    title: 'Last created',
    order: '_createdAt desc',
    limit: 10,
    types: null,
    query: null
  }

  assembleQuery = () => {
    const {query, types, order, limit} = this.props

    if (query) {
      return query
    }

    const documentTypes = schemaTypeNames.filter(typeName => {
      const schemaType = schema.get(typeName)
      return schemaType.type && schemaType.type.name === 'document'
    })

    if (types) {
      return `
        *[
          _type in ${stringifyArray(intersection(types, documentTypes))}
        ] | order(${order}) [0...${limit}]`
    }

    return `
      *[
        _type in ${stringifyArray(documentTypes)}
      ] | {_id, _type} | order(${order}) [0...${limit}]`
  }

  render() {
    const {title, types} = this.props
    const query = this.assembleQuery()

    return (

{title}

        <List className={styles.list}>
          <QueryContainer query={query}>
            {({result, loading, error, onRetry}) => {
              if (loading) {
                return <Spinner center message="Loading items…" />
              }
              const items = result ? result.documents : []
              return items.map(item => {
                const type = schema.get(item._type)
                return (
                  <Item key={item._id}>
                    <IntentLink
                      intent="edit"
                      params={{
                        type: item._type,
                        id: item._id
                      }}
                      className={styles.link}
                    >
                      <SanityPreview layout="default" type={type} value={item} key={item._id} />
                    </IntentLink>
                  </Item>
                )
              })
            }}
          </QueryContainer>
        </List>
        {types && types.length === 1 && (

            <IntentButton
              bleed
              color="primary"
              kind="simple"
              intent="create"
              params={{type: types[0]}}
            >
              Create new {types[0]}
            </IntentButton>

        )}

    )
  }
}

export default {
  name: 'document-list',
  component: DocumentList
}
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import pathModule from 'path'
import trash from 'trash'
import { connect } from 'react-redux'
import FaCog from 'react-icons/fa/cog'
import FaFolderOpen from 'react-icons/fa/arrow-up'
import IconCopy from 'react-icons/md/content-copy'
import IconCode from 'react-icons/md/code'
import IconCamera from 'react-icons/md/camera-alt'
import IconEmail from 'react-icons/md/email'
import IconAdd from 'react-icons/md/note-add'
import IconBeautify from 'react-icons/md/autorenew'
import fs from 'fs'
import { shell, clipboard } from 'electron'
import beautifyJS from 'js-beautify'

import defaultMJML from 'data/defaultMJML'

import { openModal } from 'reducers/modals'
import { addAlert } from 'reducers/alerts'
import { setPreview } from 'actions/preview'

import { fileDialog, saveDialog, fsWriteFile } from 'helpers/fs'

import Button from 'components/Button'
import ButtonDropdown from 'components/Button/ButtonDropdown'
import FilesList from 'components/FilesList'

import BackButton from './BackButton'
import SendModal from './SendModal'
import AddFileModal from './AddFileModal'
import RemoveFileModal from './RemoveFileModal'

import takeScreenshot from 'helpers/takeScreenshot'

@connect(
  state => ({
    preview: state.preview,
    previewSize: state.settings.get('previewSize'),
    beautifyOutput: state.settings.getIn(['mjml', 'beautify']),
    checkForRelativePaths: state.settings.getIn(['mjml', 'checkForRelativePaths']),
  }),
  {
    openModal,
    addAlert,
    setPreview,
  },
)
class ProjectPage extends Component {
  state = {
    path: this.props.location.query.path,
    activeFile: null,
  }

  componentDidMount() {
    this._page.focus()
  }

  componentWillUnmount() {
    this.props.setPreview(null)
  }

  handleBeautify = () => this._editor.beautify()

  handlePathChange = path => this.setState({ path, activeFile: null })

  handleClickImport = () => {
    const p = fileDialog({
      defaultPath: this.props.location.query.path,
      properties: ['openFile'],
      filters: [{ name: 'All Files', extensions: ['mjml'] }],
    })

    if (!p) {
      return
    }

    fs.readFile(p, { encoding: 'utf8' }, (err, res) => {
      if (err) {
        return
      }
      this._content = res
    })
  }

  handleAddFile = fileName => {
    fs.writeFile(fileName, defaultMJML, err => {
      if (err) {
        this.props.addAlert('Error creating file', 'error')
        throw new Error(err)
      }
      this._filelist.refresh()
    })
  }

  handleRemoveFile = async fileName => {
    try {
      if ((await trash(fileName)) === undefined) {
        throw new Error('No file was deleted')
      }
      this.props.addAlert('File successfully removed', 'success')
    } catch (e) {
      this.props.addAlert('Could not delete file', 'error')
      throw new Error(e)
    }

    this._filelist.refresh()
    this.setState({ activeFile: null })
  }

  handleOpenInBrowser = () => {
    if (process.platform === 'darwin') {
      shell.showItemInFolder(this.state.path)
    } else {
      shell.openItem(this.state.path)
    }
  }

  handleActiveFileChange = activeFile => this.setState({ activeFile })

  handleCopyHTML = () => {
    const htmlContent = this.getHTMLOutput()
    clipboard.writeText(htmlContent)
    this.props.addAlert('Copied!', 'success')
  }

  handleExportToHTML = async () => {
    if(this.props.checkForRelativePaths) this.checkForRelativePaths();
    const p = saveDialog({
      title: 'Export to HTML file',
      defaultPath: this.props.location.query.path,
      filters: [{ name: 'All Files', extensions: ['html'] }],
    })
    if (!p) {
      return
    }

    const { addAlert } = this.props

    const htmlContent = this.getHTMLOutput()

    await fsWriteFile(p, htmlContent)
    addAlert('Successfully exported HTML', 'success')
    this._filelist.refresh()
  }

  handleScreenshot = async () => {
    const { preview, previewSize, addAlert, location } = this.props

    const filename = pathModule.basename(this.state.activeFile.name, '.mjml')

    const [mobileWidth, desktopWidth] = [previewSize.get('mobile'), previewSize.get('desktop')]

    const [mobileScreenshot, desktopScreenshot] = await Promise.all([
      takeScreenshot(preview.content, mobileWidth),
      takeScreenshot(preview.content, desktopWidth),
    ])

    await Promise.all([
      fsWriteFile(pathModule.join(location.query.path, `${filename}-mobile.png`), mobileScreenshot),
      fsWriteFile(
        pathModule.join(location.query.path, `${filename}-desktop.png`),
        desktopScreenshot,
      ),
    ])

    addAlert('Successfully saved mobile and desktop screenshots', 'success')
    this._filelist.refresh()
  }

  openSettingsModal = () => this.props.openModal('settings')
  openSendModal = () => this.props.openModal('send')
  openAddFileModal = () => this.props.openModal('addFile')

  checkForRelativePaths(){
    const { preview, beautifyOutput } = this.props
    const relativePathsRegex = new RegExp(/(?:href|src)=(["'])(?!mailto|https|http|data:).*?\1/g);
    let matches = preview.content.match(relativePathsRegex);
    matches = matches.map(match=>'■ '+match);
    this.props.addAlert(['Found possible non-absolute paths:',...matches], 'error', {autoHide:false});
  }

  getHTMLOutput() {
    const { preview, beautifyOutput } = this.props
    return beautifyOutput ? beautifyJS.html(preview.content) : preview.content
  }

  render() {
    const { preview } = this.props
    const { path, activeFile } = this.state

    const rootPath = this.props.location.query.path
    const projectName = pathModule.basename(rootPath)
    const isMJMLFile = activeFile && activeFile.name.endsWith('.mjml')

    return (

 (this._page = n)}>

            <BackButton projectName={projectName} />
            <Button ghost onClick={this.openAddFileModal}>
              <IconAdd className="mr-5" />
              {'New file'}
            </Button>

            {isMJMLFile && [
              <Button key="beautify" transparent onClick={this.handleBeautify}>
                <IconBeautify style={{ marginRight: 5 }} />
                {'Beautify'}
              </Button>,
            ]}
            <Button transparent onClick={this.handleOpenInBrowser}>
              <FaFolderOpen style={{ marginRight: 5 }} />
              {'Open'}
            </Button>
            {preview &&
              preview.type === 'html' && [
                <Button key={'send'} transparent onClick={this.openSendModal}>
                  <IconEmail style={{ marginRight: 5 }} />
                  {'Send'}
                </Button>,
                <ButtonDropdown
                  ghost
                  key={'export'}
                  dropdownWidth={300}
                  actions={[
                    {
                      icon: <IconCopy />,
                      label: 'Copy HTML',
                      desc: 'Copy the result HTML to clipboard',
                      onClick: this.handleCopyHTML,
                    },
                    {
                      icon: <IconCode />,
                      label: 'Export to HTML file',
                      desc: 'Save the result HTML file to disk',
                      onClick: this.handleExportToHTML,
                    },
                    {
                      icon: <IconCamera />,
                      label: 'Screenshot',
                      desc: 'Save a screenshot of mobile & desktop result',
                      onClick: this.handleScreenshot,
                    },
                  ]}
                />,
              ]}

          <Button
            className="ml-10"
            ghost
            onClick={this.openSettingsModal}
            ref={n => (this._btnSettings = n)}
          >
            <FaCog />
          </Button>

          <FilesList
            onRef={n => (this._filelist = n)}
            onEditorRef={n => (this._editor = n)}
            withPreview
            withHome
            rootPath={rootPath}
            path={path}
            activeFile={activeFile}
            onActiveFileChange={this.handleActiveFileChange}
            onPathChange={this.handlePathChange}
            onAddClick={this.openAddModal}
            onAddFile={this.handleAddFile}
            onRemoveFile={this.handleRemoveFile}
            focusHome
          />

        <SendModal />
        <AddFileModal rootPath={path} onAdd={this.handleAddFile} />
        <RemoveFileModal rootPath={path} onRemove={this.handleRemoveFile} />

    )
  }
}

export default ProjectPage
<commit_msg>fix linting erros<commit_after>import React, { Component } from 'react'
import pathModule from 'path'
import trash from 'trash'
import { connect } from 'react-redux'
import FaCog from 'react-icons/fa/cog'
import FaFolderOpen from 'react-icons/fa/arrow-up'
import IconCopy from 'react-icons/md/content-copy'
import IconCode from 'react-icons/md/code'
import IconCamera from 'react-icons/md/camera-alt'
import IconEmail from 'react-icons/md/email'
import IconAdd from 'react-icons/md/note-add'
import IconBeautify from 'react-icons/md/autorenew'
import fs from 'fs'
import { shell, clipboard } from 'electron'
import beautifyJS from 'js-beautify'

import defaultMJML from 'data/defaultMJML'

import { openModal } from 'reducers/modals'
import { addAlert } from 'reducers/alerts'
import { setPreview } from 'actions/preview'

import { fileDialog, saveDialog, fsWriteFile } from 'helpers/fs'

import Button from 'components/Button'
import ButtonDropdown from 'components/Button/ButtonDropdown'
import FilesList from 'components/FilesList'

import BackButton from './BackButton'
import SendModal from './SendModal'
import AddFileModal from './AddFileModal'
import RemoveFileModal from './RemoveFileModal'

import takeScreenshot from 'helpers/takeScreenshot'

@connect(
  state => ({
    preview: state.preview,
    previewSize: state.settings.get('previewSize'),
    beautifyOutput: state.settings.getIn(['mjml', 'beautify']),
    checkForRelativePaths: state.settings.getIn(['mjml', 'checkForRelativePaths']),
  }),
  {
    openModal,
    addAlert,
    setPreview,
  },
)
class ProjectPage extends Component {
  state = {
    path: this.props.location.query.path,
    activeFile: null,
  }

  componentDidMount() {
    this._page.focus()
  }

  componentWillUnmount() {
    this.props.setPreview(null)
  }

  handleBeautify = () => this._editor.beautify()

  handlePathChange = path => this.setState({ path, activeFile: null })

  handleClickImport = () => {
    const p = fileDialog({
      defaultPath: this.props.location.query.path,
      properties: ['openFile'],
      filters: [{ name: 'All Files', extensions: ['mjml'] }],
    })

    if (!p) {
      return
    }

    fs.readFile(p, { encoding: 'utf8' }, (err, res) => {
      if (err) {
        return
      }
      this._content = res
    })
  }

  handleAddFile = fileName => {
    fs.writeFile(fileName, defaultMJML, err => {
      if (err) {
        this.props.addAlert('Error creating file', 'error')
        throw new Error(err)
      }
      this._filelist.refresh()
    })
  }

  handleRemoveFile = async fileName => {
    try {
      if ((await trash(fileName)) === undefined) {
        throw new Error('No file was deleted')
      }
      this.props.addAlert('File successfully removed', 'success')
    } catch (e) {
      this.props.addAlert('Could not delete file', 'error')
      throw new Error(e)
    }

    this._filelist.refresh()
    this.setState({ activeFile: null })
  }

  handleOpenInBrowser = () => {
    if (process.platform === 'darwin') {
      shell.showItemInFolder(this.state.path)
    } else {
      shell.openItem(this.state.path)
    }
  }

  handleActiveFileChange = activeFile => this.setState({ activeFile })

  handleCopyHTML = () => {
    const htmlContent = this.getHTMLOutput()
    clipboard.writeText(htmlContent)
    this.props.addAlert('Copied!', 'success')
  }

  handleExportToHTML = async () => {
    if(this.props.checkForRelativePaths) this.checkForRelativePaths();
    const p = saveDialog({
      title: 'Export to HTML file',
      defaultPath: this.props.location.query.path,
      filters: [{ name: 'All Files', extensions: ['html'] }],
    })
    if (!p) {
      return
    }

    const { addAlert } = this.props

    const htmlContent = this.getHTMLOutput()

    await fsWriteFile(p, htmlContent)
    addAlert('Successfully exported HTML', 'success')
    this._filelist.refresh()
  }

  handleScreenshot = async () => {
    const { preview, previewSize, addAlert, location } = this.props

    const filename = pathModule.basename(this.state.activeFile.name, '.mjml')

    const [mobileWidth, desktopWidth] = [previewSize.get('mobile'), previewSize.get('desktop')]

    const [mobileScreenshot, desktopScreenshot] = await Promise.all([
      takeScreenshot(preview.content, mobileWidth),
      takeScreenshot(preview.content, desktopWidth),
    ])

    await Promise.all([
      fsWriteFile(pathModule.join(location.query.path, `${filename}-mobile.png`), mobileScreenshot),
      fsWriteFile(
        pathModule.join(location.query.path, `${filename}-desktop.png`),
        desktopScreenshot,
      ),
    ])

    addAlert('Successfully saved mobile and desktop screenshots', 'success')
    this._filelist.refresh()
  }

  openSettingsModal = () => this.props.openModal('settings')
  openSendModal = () => this.props.openModal('send')
  openAddFileModal = () => this.props.openModal('addFile')

  checkForRelativePaths(){
    const { preview } = this.props
    const relativePathsRegex = new RegExp(/(?:href|src)=(["'])(?!mailto|https|http|data:).*?\1/g);
    let matches = preview.content.match(relativePathsRegex);
    matches = matches.map(match=>`■ ${match}`);
    this.props.addAlert(['Found possible non-absolute paths:',...matches], 'error', {autoHide:false});
  }

  getHTMLOutput() {
    const { preview, beautifyOutput } = this.props
    return beautifyOutput ? beautifyJS.html(preview.content) : preview.content
  }

  render() {
    const { preview } = this.props
    const { path, activeFile } = this.state

    const rootPath = this.props.location.query.path
    const projectName = pathModule.basename(rootPath)
    const isMJMLFile = activeFile && activeFile.name.endsWith('.mjml')

    return (

 (this._page = n)}>

            <BackButton projectName={projectName} />
            <Button ghost onClick={this.openAddFileModal}>
              <IconAdd className="mr-5" />
              {'New file'}
            </Button>

            {isMJMLFile && [
              <Button key="beautify" transparent onClick={this.handleBeautify}>
                <IconBeautify style={{ marginRight: 5 }} />
                {'Beautify'}
              </Button>,
            ]}
            <Button transparent onClick={this.handleOpenInBrowser}>
              <FaFolderOpen style={{ marginRight: 5 }} />
              {'Open'}
            </Button>
            {preview &&
              preview.type === 'html' && [
                <Button key={'send'} transparent onClick={this.openSendModal}>
                  <IconEmail style={{ marginRight: 5 }} />
                  {'Send'}
                </Button>,
                <ButtonDropdown
                  ghost
                  key={'export'}
                  dropdownWidth={300}
                  actions={[
                    {
                      icon: <IconCopy />,
                      label: 'Copy HTML',
                      desc: 'Copy the result HTML to clipboard',
                      onClick: this.handleCopyHTML,
                    },
                    {
                      icon: <IconCode />,
                      label: 'Export to HTML file',
                      desc: 'Save the result HTML file to disk',
                      onClick: this.handleExportToHTML,
                    },
                    {
                      icon: <IconCamera />,
                      label: 'Screenshot',
                      desc: 'Save a screenshot of mobile & desktop result',
                      onClick: this.handleScreenshot,
                    },
                  ]}
                />,
              ]}

          <Button
            className="ml-10"
            ghost
            onClick={this.openSettingsModal}
            ref={n => (this._btnSettings = n)}
          >
            <FaCog />
          </Button>

          <FilesList
            onRef={n => (this._filelist = n)}
            onEditorRef={n => (this._editor = n)}
            withPreview
            withHome
            rootPath={rootPath}
            path={path}
            activeFile={activeFile}
            onActiveFileChange={this.handleActiveFileChange}
            onPathChange={this.handlePathChange}
            onAddClick={this.openAddModal}
            onAddFile={this.handleAddFile}
            onRemoveFile={this.handleRemoveFile}
            focusHome
          />

        <SendModal />
        <AddFileModal rootPath={path} onAdd={this.handleAddFile} />
        <RemoveFileModal rootPath={path} onRemove={this.handleRemoveFile} />

    )
  }
}

export default ProjectPage
<|endoftext|>


<commit_before>'use strict';
const fs = require('fs');
const chalk = require('chalk');
const { IS_WINDOWS, indexToPos } = require('../utils.js');

/**
 * @typedef {import('../utils').Logger} Logger
 */

/**
 * @param {string} filename
 * @param {Logger} logger
 */
function processData(filename, logger) {
  let hasErrors = false;

  let actual = fs.readFileSync(filename, 'utf-8').trim();
  /** @type {import('../../types').CompatData} */
  const dataObject = JSON.parse(actual);
  let expected = JSON.stringify(dataObject, null, 2);

  // prevent false positives from git.core.autocrlf on Windows
  if (IS_WINDOWS) {
    actual = actual.replace(/\r/g, '');
    expected = expected.replace(/\r/g, '');
  }

  /** @type {(regexp: string|RegExp, matchHandler: (match: RegExpMatchArray) => void) => void} */
  const processLinks = PROCESS_LINKS.bind(this, actual);

  processLinks(
    String.raw`https?://bugzilla\.mozilla\.org/show_bug\.cgi\?id=(\d+)`,
    match => {
      // use https://bugzil.la/1000000 instead
      hasErrors = true;
      logger.error(
        chalk`{red → ${indexToPos(
          actual,
          match.index,
        )} – Use shortenable URL ({yellow ${
          match[0]
        }} → {green {bold https://bugzil.la/}${match[1]}}).}`,
      );
    },
  );

  processLinks(
    String.raw`https?://bugs\.chromium\.org/p/chromium/issues/detail\?id=(\d+)`,
    match => {
      // use https://crbug.com/100000 instead
      hasErrors = true;
      logger.error(
        chalk`{red → ${indexToPos(
          actual,
          match.index,
        )} – Use shortenable URL ({yellow ${
          match[0]
        }} → {green {bold https://crbug.com/}${match[1]}}).}`,
      );
    },
  );

  processLinks(
    String.raw`https?://bugs\.webkit\.org/show_bug\.cgi\?id=(\d+)`,
    match => {
      // use https://webkit.org/b/100000 instead
      hasErrors = true;
      logger.error(
        chalk`{red → ${indexToPos(
          actual,
          match.index,
        )} – Use shortenable URL ({yellow ${
          match[0]
        }} → {green {bold https://webkit.org/b/}${match[1]}}).}`,
      );
    },
  );

  processLinks(
    // Bugzil.la links should use HTTPS and have "bug ###" as link text ("Bug ###" only at the begin of notes/sentences).
    String.raw`(....)<a href='(https?)://(bugzil\.la|crbug\.com|webkit\.org/b)/(\d+)'>(.*?)</a>`,
    match => {
      const [, before, protocol, domain, bugId, linkText] = match;

      if (protocol !== 'https') {
        hasErrors = true;
        logger.error(
          chalk`{red → ${indexToPos(
            actual,
            match.index,
          )} – Use HTTPS URL ({yellow http://${domain}/${bugId}} → {green http{bold s}://${domain}/${bugId}}).}`,
        );
      }

      if (domain !== 'bugzil.la') {
        return;
      }

      if (/^bug $/.test(before)) {
        hasErrors = true;
        logger.error(
          chalk`{red → ${indexToPos(
            actual,
            match.index,
          )} – Move word "bug" into link text ({yellow "${before}${linkText}"} → {green "{bold ${before}}${bugId}"}).}`,
        );
      } else if (linkText === `Bug ${bugId}`) {
        if (!/(\. |")$/.test(before)) {
          hasErrors = true;
          logger.error(
            chalk`{red → ${indexToPos(
              actual,
              match.index,
            )} – Use lowercase "bug" word within sentence ({yellow "Bug ${bugId}"} → {green "{bold bug} ${bugId}"}).}`,
          );
        }
      } else if (linkText !== `bug ${bugId}`) {
        hasErrors = true;
        logger.error(
          chalk`{red → ${indexToPos(
            actual,
            match.index,
          )} – Use standard link text ({yellow "${linkText}"} → {green "bug ${bugId}"}).}`,
        );
      }
    },
  );

  processLinks(
    String.raw`\b(https?)://((?:[a-z][a-z0-9-]*\.)*)developer.mozilla.org/(.*?)(?=["'\s])`,
    match => {
      const [url, protocol, subdomain, path] = match;
      const [, locale, expectedPath_] = /^(?:(\w\w(?:-\w\w)?)\/)?(.*)$/.exec(
        path,
      );
      let expectedPath = expectedPath_;

      if (!expectedPath.startsWith('docs/')) {
        // Convert legacy zone URLs (see https://bugzil.la/1462475):
        const [zone, index] = /** @return {[string|null, number]} */ (() => {
          const match = expectedPath.match(
            /\b(Add-ons|Apps|Archive|Firefox|Learn|Web)\b/,
          );
          return match ? [match[1], match.index] : [null, -1];
        })();
        if (index >= 0) {
          expectedPath = expectedPath.substring(index);
          switch (zone) {
            case 'Add-ons':
            case 'Firefox':
              expectedPath = 'Mozilla/' + expectedPath;
              break;
            case 'Apps':
              expectedPath = 'Web/' + expectedPath;
              break;
          }
        }
        expectedPath = 'docs/' + expectedPath;
      }
      const pos = indexToPos(match.input, match.index);

      if (protocol !== 'https') {
        hasErrors = true;
        logger.error(
          chalk`{red → ${pos} – Use HTTPS MDN URL ({yellow ${protocol}://developer.mozilla.org/${path}} → {green https://developer.mozilla.org/${expectedPath}}).}`,
        );
      }

      if (subdomain) {
        hasErrors = true;
        logger.error(
          chalk`{red → ${pos} - Use correct MDN domain ({yellow ${protocol}://{red ${subdomain}}developer.mozilla.org/${path}} → {green https://developer.mozilla.org/${expectedPath}})}`,
        );
      }

      if (path !== expectedPath) {
        hasErrors = true;
        logger.error(
          chalk`{red → ${pos} – Use ${
            locale ? 'non-localized' : 'correct'
          } MDN URL ({yellow ${url}} → {green https://developer.mozilla.org/${expectedPath}}).}`,
        );
      }
    },
  );

  processLinks(
    String.raw`https?://developer.microsoft.com/(\w\w-\w\w)/(.*?)(?=["'\s])`,
    match => {
      hasErrors = true;
      logger.error(
        chalk`{red → ${indexToPos(
          actual,
          match.index,
        )} – Use non-localized Microsoft Developer URL ({yellow ${
          match[0]
        }} → {green https://developer.microsoft.com/${match[2]}}).}`,
      );
    },
  );

  return hasErrors;
}

/**
 * @param {string} actual
 * @param {string|RegExp} regexp
 * @param {(match: RegExpExecArray) => void} matchHandler
 */
const PROCESS_LINKS = function processLinks(actual, regexp, matchHandler) {
  const re = new RegExp(regexp, 'g');
  /** @type {RegExpExecArray} */
  let match;
  while ((match = re.exec(actual)) !== null) {
    matchHandler(match);
  }
};

/**
 * @param {string} filename
 */
function testLinks(filename) {
  /** @type {string[]} */
  const errors = [];
  const logger = {
    /** @param {...unknown} message */
    error: (...message) => {
      errors.push(message.join(' '));
    },
  };

  processData(filename, logger);

  if (errors.length) {
    console.error(
      chalk`{red   Links – {bold ${errors.length}} ${
        errors.length === 1 ? 'error' : 'errors'
      }:}`,
    );
    for (const error of errors) {
      console.error(`  ${error}`);
    }
    return true;
  }
  return false;
}

module.exports = testLinks;
<commit_msg>Refactor link tests (#5187)<commit_after>'use strict';
const fs = require('fs');
const chalk = require('chalk');
const { IS_WINDOWS, indexToPos, indexToPosRaw } = require('../utils.js');

/**
 * @typedef {import('../utils').Logger} Logger
 */

/**
 * @param {string} filename
 * @param {Logger} logger
 */
function processData(filename) {
  let errors = [];

  let actual = fs.readFileSync(filename, 'utf-8').trim();

  // prevent false positives from git.core.autocrlf on Windows
  if (IS_WINDOWS) {
    actual = actual.replace(/\r/g, '');
  }

  processLink(
    // use https://bugzil.la/1000000 instead
    errors,
    actual,
    String.raw`https?://bugzilla\.mozilla\.org/show_bug\.cgi\?id=(\d+)`,
    match => {
      return {
        issue: 'Use shortenable URL',
        expected: `https://bugzil.la/${match[1]}`,
      };
    },
  );

  processLink(
    // use https://crbug.com/100000 instead
    errors,
    actual,
    String.raw`https?://(bugs\.chromium\.org|code\.google\.com)/p/chromium/issues/detail\?id=(\d+)`,
    match => {
      return {
        issue: 'Use shortenable URL',
        expected: `https://crbug.com/${match[2]}`,
      };
    },
  );

  processLink(
    // use https://webkit.org/b/100000 instead
    errors,
    actual,
    String.raw`https?://bugs\.webkit\.org/show_bug\.cgi\?id=(\d+)`,
    match => {
      return {
        issue: 'Use shortenable URL',
        expected: `https://webkit.org/b/${match[1]}`,
      };
    },
  );

  processLink(
    // Bug links should use HTTPS and have "bug ###" as link text ("Bug ###" only at the begin of notes/sentences).
    errors,
    actual,
    String.raw`(....)<a href='((https?)://(bugzil\.la|crbug\.com|webkit\.org/b)/(\d+))'>(.*?)</a>`,
    match => {
      const [, before, url, protocol, domain, bugId, linkText] = match;

      if (protocol !== 'https') {
        return {
          issue: 'Use HTTPS for bug links',
          expected: `https://${domain}/${bugId}`,
          actualLink: url,
        };
      }

      if (domain == 'bugzil.la') {
        if (/^bug $/.test(before)) {
          return {
            issue: 'Move word "bug" into link text',
            expected: `<a href='...'>${before}${bugId}</a>`,
            actualLink: `${before}<a href='...'>${linkText}</a>`,
          };
        } else if (linkText === `Bug ${bugId}`) {
          if (!/(\. |")$/.test(before)) {
            return {
              issue: 'Use lowercase "bug" word within sentence',
              expected: `bug ${bugId}`,
              actualLink: `Bug ${bugId}`,
            };
          }
        } else if (linkText !== `bug ${bugId}`) {
          return {
            issue: 'Use standard link text',
            expected: `bug ${bugId}`,
            actualLink: linkText,
          };
        }
      }
    },
  );

  processLink(
    errors,
    actual,
    String.raw`\b(https?)://((?:[a-z][a-z0-9-]*\.)*)developer.mozilla.org/(.*?)(?=["'\s])`,
    match => {
      const [, protocol, subdomain, path] = match;
      const [, locale, expectedPath_] = /^(?:(\w\w(?:-\w\w)?)\/)?(.*)$/.exec(
        path,
      );
      let expectedPath = expectedPath_;

      if (!expectedPath.startsWith('docs/')) {
        // Convert legacy zone URLs (see https://bugzil.la/1462475):
        const [zone, index] = /** @return {[string|null, number]} */ (() => {
          const match = expectedPath.match(
            /\b(Add-ons|Apps|Archive|Firefox|Learn|Web)\b/,
          );
          return match ? [match[1], match.index] : [null, -1];
        })();
        if (index >= 0) {
          expectedPath = expectedPath.substring(index);
          switch (zone) {
            case 'Add-ons':
            case 'Firefox':
              expectedPath = 'Mozilla/' + expectedPath;
              break;
            case 'Apps':
              expectedPath = 'Web/' + expectedPath;
              break;
          }
        }
        expectedPath = 'docs/' + expectedPath;
      }

      if (protocol !== 'https') {
        return {
          issue: 'Use HTTPS MDN URL',
          expected: `https://developer.mozilla.org/${expectedPath}`,
        };
      }

      if (subdomain) {
        return {
          issue: 'Use correct MDN domain',
          expected: `https://developer.mozilla.org/${expectedPath}`,
        };
      }

      if (path !== expectedPath) {
        return {
          issue: `Use ${locale ? 'non-localized' : 'correct'} MDN URL`,
          expected: `https://developer.mozilla.org/${expectedPath}`,
        };
      }
    },
  );

  processLink(
    errors,
    actual,
    String.raw`https?://developer.microsoft.com/(\w\w-\w\w)/(.*?)(?=["'\s])`,
    match => {
      return {
        issue: 'Use non-localized Microsoft Developer URL',
        expected: `https://developer.microsoft.com/${match[2]}`,
      };
    },
  );

  return errors;
}

/**
 * @param {Object[]} errors
 * @param {string} actual
 * @param {string|RegExp} regexp
 * @param {(match: RegExpExecArray) => Object} matchHandler
 */
function processLink(errors, actual, regexp, matchHandler) {
  const re = new RegExp(regexp, 'g');
  /** @type {RegExpExecArray} */
  let match;
  while ((match = re.exec(actual)) !== null) {
    let pos = indexToPosRaw(actual, match.index);
    let posString = indexToPos(actual, match.index);
    let result = matchHandler(match);

    if (result) {
      let { issue, expected, actualLink = match[0] } = result;
      errors.push({
        issue: issue,
        pos: pos,
        posString: posString,
        actual: actualLink,
        expected: expected,
      });
    }
  }
}

/**
 * @param {string} filename
 */
function testLinks(filename) {
  /** @type {Object[]} */
  let errors = processData(filename);

  if (errors.length) {
    console.error(
      chalk`{red   Links – {bold ${errors.length}} ${
        errors.length === 1 ? 'error' : 'errors'
      }:}`,
    );
    for (const error of errors) {
      console.error(
        chalk`  {red → ${error.posString} – ${error.issue} ({yellow ${error.actual}} → {green ${error.expected}}).}`,
      );
    }
    return true;
  }
  return false;
}

module.exports = testLinks;
<|endoftext|>


<commit_before>WysiHat.BrowserFeatures = (function() {
  function createTmpIframe(callback) {
    var frame, frameDocument, frameWindow;

    frame = new Element('iframe');
    frame.setStyle({
      position: 'absolute',
      left: '-1000px'
    });

    frame.onFrameLoaded(function() {
      if (typeof frame.contentDocument !== 'undefined') {
        frameDocument = frame.contentDocument;
      } else if (typeof frame.contentWindow !== 'undefined' && typeof frame.contentWindow.document !== 'undefined') {
        frameDocument = frame.contentWindow.document;
      }

      if (typeof frame.contentDocument !== 'undefined' && typeof frame.contentDocument.defaultView !== 'undefined') {
        frameWindow = frame.contentDocument.defaultView;
      } else if (typeof frame.contentWindow.document  !== 'undefined') {
        frameWindow = frame.contentWindow;
      }

      frameDocument.designMode = 'on';

      callback(frameDocument, frameWindow);

      frame.remove();
    });

    $(document.body).insert(frame);
  }

  var features = {};

  function detectParagraphType(document) {
    document.body.innerHTML = '';
    document.execCommand('insertparagraph', false, null);

    var tagName;
    element = document.body.childNodes[0];
    if (element && element.tagName)
      tagName = element.tagName.toLowerCase();

    if (tagName == 'div')
      features.paragraphType = "div";
    else if (document.body.innerHTML == "

")
      features.paragraphType = "br";
    else
      features.paragraphType = "p";
  }

  function detectIndentType(document) {
    document.body.innerHTML = 'tab';
    document.execCommand('indent', false, null);

    var tagName;
    element = document.body.childNodes[0];
    if (element && element.tagName)
      tagName = element.tagName.toLowerCase();
    features.indentInsertsBlockquote = (tagName == 'blockquote');
  }

  features.run = function run() {
    if (features.finished) return;

    createTmpIframe(function(document, window) {
      detectParagraphType(document);
      detectIndentType(document);

      features.finished = true;
    });
  }

  return features;
})();
<commit_msg>frameWindow is unused<commit_after>WysiHat.BrowserFeatures = (function() {
  function createTmpIframe(callback) {
    var frame, frameDocument;

    frame = new Element('iframe');
    frame.setStyle({
      position: 'absolute',
      left: '-1000px'
    });

    frame.onFrameLoaded(function() {
      if (typeof frame.contentDocument !== 'undefined') {
        frameDocument = frame.contentDocument;
      } else if (typeof frame.contentWindow !== 'undefined' && typeof frame.contentWindow.document !== 'undefined') {
        frameDocument = frame.contentWindow.document;
      }

      frameDocument.designMode = 'on';

      callback(frameDocument);

      frame.remove();
    });

    $(document.body).insert(frame);
  }

  var features = {};

  function detectParagraphType(document) {
    document.body.innerHTML = '';
    document.execCommand('insertparagraph', false, null);

    var tagName;
    element = document.body.childNodes[0];
    if (element && element.tagName)
      tagName = element.tagName.toLowerCase();

    if (tagName == 'div')
      features.paragraphType = "div";
    else if (document.body.innerHTML == "

")
      features.paragraphType = "br";
    else
      features.paragraphType = "p";
  }

  function detectIndentType(document) {
    document.body.innerHTML = 'tab';
    document.execCommand('indent', false, null);

    var tagName;
    element = document.body.childNodes[0];
    if (element && element.tagName)
      tagName = element.tagName.toLowerCase();
    features.indentInsertsBlockquote = (tagName == 'blockquote');
  }

  features.run = function run() {
    if (features.finished) return;

    createTmpIframe(function(document) {
      detectParagraphType(document);
      detectIndentType(document);

      features.finished = true;
    });
  }

  return features;
})();
<|endoftext|>


<commit_before>// @flow
import React from 'react'
import { createRouter, mountInProvider } from '../testUtil'
import Link from './Link'

describe('Link', () => {
  let router

  beforeEach(() => {
    router = createRouter( [{ path: '', match: 'full'}, { path: 'foo' }])
    return router.start()
  })

  afterEach(() => {
    router.stop()
  })

  test('delegates to router to create href', () => {
    (router: any).createHref = jest.fn(() => '/whatever')

    const wrapper = mountInProvider(router)(

        <Link className="index" to="/">Index</Link>

    )

    expect(wrapper.html()).toMatch(/whatever/)
  })

  test('handles clicks', async () => {
    const wrapper = mountInProvider(router)(

        <Link className="index" to="/">Index</Link>
        <Link className="foo" to="/foo">Foo</Link>

    )

    wrapper.find('.foo').simulate('click', { button: 0 })
    await delay(0)

    expect(router._store.location.pathname).toEqual('/foo')

    wrapper.find('.index').simulate('click', { button: 0 })
    await delay(0)

    expect(router._store.location.pathname).toEqual('/')
  })

  test('supports target prop to skip router', async () => {
    const wrapper = mountInProvider(router)(

        <Link target="_self" className="foo" to="/foo">Foo</Link>

    )

    wrapper.find('.foo').simulate('click', { button: 0 })
    await delay(0)

    expect(router._store.location.pathname).toEqual('/')
  })

  test('supports onClick prop', async () => {
    const spy = jest.fn()
    const wrapper = mountInProvider(router)(

        <Link onClick={spy} className="foo" to="/foo">Foo</Link>

    )

    wrapper.find('.foo').simulate('click', { button: 0 })
    await delay(0)

    expect(spy).toHaveBeenCalled()
  })

  test('supports onMouseEnter prop', async () => {
    const spy = jest.fn()
    const wrapper = mountInProvider(router)(

        <Link onMouseEnter={spy} className="foo" to="/foo">Foo</Link>

    )

    wrapper.find('.foo').simulate('mouseenter')
    await delay(0)

    expect(spy).toHaveBeenCalled()
  })

  test('supports onMouseLeave prop', async () => {
    const spy = jest.fn()
    const wrapper = mountInProvider(router)(

        <Link onMouseLeave={spy} className="foo" to="/foo">Foo</Link>

    )

    wrapper.find('.foo').simulate('mouseleave')
    await delay(0)

    expect(spy).toHaveBeenCalled()
  })

  test('supports Location objects', async () => {
    const location = {
      pathname: '/foo',
      hash: '#hey',
      query: {
        a: 1,
        b: 2
      }
    }
    const spy = jest.fn()
    const wrapper = mountInProvider(router)(

        <Link onClick={spy} className="foo" to={location}>Foo</Link>

    )

    wrapper.find('.foo').simulate('click', { button: 0 })
    await delay(0)

    expect(spy).toHaveBeenCalled()
    expect(router._store.location.pathname).toEqual('/foo')
    expect(router._store.location.hash).toEqual('#hey')
    expect(router._store.location.query).toEqual({ a: '1', b: '2' })
    expect(router._store.location.search).toEqual('?a=1&b=2')
  })

  test('supports Location objects with state', async () => {
    const afterSpy = jest.fn()

    const location = {
      pathname: '/foo',
      state: {
        scrollTo: {
          x: 0,
          y: 50
        },
        after: function() {
          afterSpy()
          return this.scrollTo.y
        }
      }
    }
    const spy = jest.fn()
    const wrapper = mountInProvider(router)(

        <Link onClick={spy} className="foo" to={location}>Foo</Link>

    )

    wrapper.find('.foo').simulate('click', { button: 0 })
    await delay(0)

    expect(spy).toHaveBeenCalled()
    expect(router._store.location.pathname).toEqual('/foo')

    const state = router._store.location.state || {}

    expect(state.scrollTo).toEqual({ x: 0, y: 50 })
    expect(state.after()).toEqual(50)
    expect(afterSpy).toHaveBeenCalled()
  })
})

function delay(ms: number) {
  return new Promise(res => {
    setTimeout(res, ms)
  })
}
<commit_msg>Fixes Link tests.<commit_after>// @flow
import React from 'react'
import { createRouter, mountInProvider } from '../testUtil'
import Link from './Link'

describe('Link', () => {
  let router

  beforeEach(() => {
    router = createRouter( [{ path: '', match: 'full'}, { path: 'foo' }])
    return router.start()
  })

  afterEach(() => {
    router.stop()
  })

  test('delegates to router to create href', () => {
    (router: any).createHref = jest.fn(() => '/whatever')

    const wrapper = mountInProvider(router)(

        <Link className="index" to="/">Index</Link>

    )

    expect(wrapper.html()).toMatch(/whatever/)
  })

  test('handles clicks', async () => {
    const wrapper = mountInProvider(router)(

        <Link className="index" to="/">Index</Link>
        <Link className="foo" to="/foo">Foo</Link>

    )

    wrapper.find('.foo').hostNodes().simulate('click', { button: 0 })
    await delay(0)

    expect(router._store.location.pathname).toEqual('/foo')

    wrapper.find('.index').hostNodes().simulate('click', { button: 0 })
    await delay(0)

    expect(router._store.location.pathname).toEqual('/')
  })

  test('supports target prop to skip router', async () => {
    const wrapper = mountInProvider(router)(

        <Link target="_self" className="foo" to="/foo">Foo</Link>

    )

    wrapper.find('.foo').hostNodes().simulate('click', { button: 0 })
    await delay(0)

    expect(router._store.location.pathname).toEqual('/')
  })

  test('supports onClick prop', async () => {
    const spy = jest.fn()
    const wrapper = mountInProvider(router)(

        <Link onClick={spy} className="foo" to="/foo">Foo</Link>

    )

    wrapper.find('.foo').hostNodes().simulate('click', { button: 0 })
    await delay(0)

    expect(spy).toHaveBeenCalled()
  })

  test('supports onMouseEnter prop', async () => {
    const spy = jest.fn()
    const wrapper = mountInProvider(router)(

        <Link onMouseEnter={spy} className="foo" to="/foo">Foo</Link>

    )

    wrapper.find('.foo').hostNodes().simulate('mouseenter')
    await delay(0)

    expect(spy).toHaveBeenCalled()
  })

  test('supports onMouseLeave prop', async () => {
    const spy = jest.fn()
    const wrapper = mountInProvider(router)(

        <Link onMouseLeave={spy} className="foo" to="/foo">Foo</Link>

    )

    wrapper.find('.foo').hostNodes().simulate('mouseleave')
    await delay(0)

    expect(spy).toHaveBeenCalled()
  })

  test('supports Location objects', async () => {
    const location = {
      pathname: '/foo',
      hash: '#hey',
      query: {
        a: 1,
        b: 2
      }
    }
    const spy = jest.fn()
    const wrapper = mountInProvider(router)(

        <Link onClick={spy} className="foo" to={location}>Foo</Link>

    )

    wrapper.find('.foo').hostNodes().simulate('click', { button: 0 })
    await delay(0)

    expect(spy).toHaveBeenCalled()
    expect(router._store.location.pathname).toEqual('/foo')
    expect(router._store.location.hash).toEqual('#hey')
    expect(router._store.location.query).toEqual({ a: '1', b: '2' })
    expect(router._store.location.search).toEqual('?a=1&b=2')
  })

  test('supports Location objects with state', async () => {
    const afterSpy = jest.fn()

    const location = {
      pathname: '/foo',
      state: {
        scrollTo: {
          x: 0,
          y: 50
        },
        after: function() {
          afterSpy()
          return this.scrollTo.y
        }
      }
    }
    const spy = jest.fn()
    const wrapper = mountInProvider(router)(

        <Link onClick={spy} className="foo" to={location}>Foo</Link>

    )

    wrapper.find('.foo').hostNodes().simulate('click', { button: 0 })
    await delay(0)

    expect(spy).toHaveBeenCalled()
    expect(router._store.location.pathname).toEqual('/foo')

    const state = router._store.location.state || {}

    expect(state.scrollTo).toEqual({ x: 0, y: 50 })
    expect(state.after()).toEqual(50)
    expect(afterSpy).toHaveBeenCalled()
  })
})

function delay(ms: number) {
  return new Promise(res => {
    setTimeout(res, ms)
  })
}
<|endoftext|>


<commit_before>'use strict'

const emitter = require('global-queue');
const patchwerk = require('patchwerk')(emitter);

let ServiceApi = require('resource-management-framework')
	.ServiceApi;

class SharedEntities {
	constructor() {
		this.emitter = message_bus;
	}

	init() {
		this.iris = new ServiceApi();
		this.iris.initContent();
	}

	//API

	actionFieldsDescription({
		workstation
	}) {
		return {};
	}

	makeResponse(namespace, entities) {
		return {
			namespace,
			entities
		}
	}

	actionServices({
		workstation
	}) {
		return Promise.props({
				ws: this.emitter.addTask('workstation', {
					_action: 'workstation',
					workstation
				}),
				services: this.iris.getServiceIds()
			})
			.then(({
				ws,
				services
			}) => {
				let keys = ws.provides || services;
				return this.iris.getService({
					keys
				});
			})
			.then(entities => this.makeResponse('services', entities));
	}

	actionOffice({
		workstation
	}) {
		return this.emitter.addTask('workstation', {
				_action: 'workstation-organization-data',
				workstation
			})
			.then(res => res[workstation])
			.then(({
				ws,
				org_addr,
				org_chain,
				org_merged
			}) => this.makeResponse('office', org_merged));
	}

	actionOrganizationChain({
		workstation
	}) {
		console.log("SE CHAIN", workstation);
		return this.emitter.addTask('workstation', {
				_action: 'workstation-organization-data',
				workstation
			})
			.then(res => res[workstation])
			.then(({
				ws,
				org_addr,
				org_chain,
				org_merged
			}) => this.makeResponse('hierarchy', org_chain));
	}

	actionTimezone({
		workstation
	}) {
		console.log("SE TIMEZONE");

		return this.emitter.addTask('workstation', {
				_action: 'workstation-organization-data',
				workstation
			})
			.then(res => res[workstation])
			.then(({
				ws,
				org_addr,
				org_chain,
				org_merged
			}) => {
				let tm = moment.utc();
				return {
					timezone: org_merged.org_timezone,
					current_time: tm.format("x")
				};
			}).then(entities => this.makeResponse('timezone', entities));
	}

	actionPriorities({
		workstation
	}) {
		console.log("SE PRIORITIES");

		return this.emitter.addTask('workstation', {
				_action: 'workstation-organization-data',
				workstation
			})
			.then(res => res[workstation])
			.then(({
				ws,
				org_addr,
				org_chain,
				org_merged
			}) => {
				return this.iris.getGlobal('priority_description');
			})
			.then(entities => this.makeResponse('priorities', entities));
	}

	actionWorkstations({
		workstation,
		department
	}) {
		let getDepartment = _.isEmpty(department) ? this.emitter.addTask('workstation', {
			_action: 'workstation-organization-data',
			workstation
		}).then(res => res[workstation].ws.attached_to) : Promise.resolve(department);

		return getDepartment.then(res => {
				return patchwerk.get('workstation', {
					counter: '*',
					type: ['control-panel', 'terminal', 'reception'],
					department: res
				});
			})
			.then(entities => this.makeResponse('workstations', _.keyBy(entities, '@id')))
	}

	actionOperators({
		workstation,
		department
	}) {
		console.log('SE operators');
		let getDepartment = _.isEmpty(department) ? this.emitter.addTask('workstation', {
			_action: 'workstation-organization-data',
			workstation
		}).then(res => res[workstation].ws.attached_to) : Promise.resolve(department);

		return getDepartment.then(res => {
				return patchwerk.get('operator', {
					counter: '*',
					department: res
				});
			})
			.then(entities => this.makeResponse('operators', _.keyBy(entities, '@id')))
	}
}

module.exports = SharedEntities;
<commit_msg>action qa-questions<commit_after>'use strict'

const emitter = require('global-queue');
const patchwerk = require('patchwerk')(emitter);

let ServiceApi = require('resource-management-framework')
	.ServiceApi;

class SharedEntities {
	constructor() {
		this.emitter = message_bus;
	}

	init() {
		this.iris = new ServiceApi();
		this.iris.initContent();
	}

	//API

	actionFieldsDescription({
		workstation
	}) {
		return {};
	}

	makeResponse(namespace, entities) {
		return {
			namespace,
			entities
		}
	}

	actionServices({
		workstation
	}) {
		return Promise.props({
				ws: this.emitter.addTask('workstation', {
					_action: 'workstation',
					workstation
				}),
				services: this.iris.getServiceIds()
			})
			.then(({
				ws,
				services
			}) => {
				let keys = ws.provides || services;
				return this.iris.getService({
					keys
				});
			})
			.then(entities => this.makeResponse('services', entities));
	}

	actionOffice({
		workstation
	}) {
		return this.emitter.addTask('workstation', {
				_action: 'workstation-organization-data',
				workstation
			})
			.then(res => res[workstation])
			.then(({
				ws,
				org_addr,
				org_chain,
				org_merged
			}) => this.makeResponse('office', org_merged));
	}

	actionOrganizationChain({
		workstation
	}) {
		console.log("SE CHAIN", workstation);
		return this.emitter.addTask('workstation', {
				_action: 'workstation-organization-data',
				workstation
			})
			.then(res => res[workstation])
			.then(({
				ws,
				org_addr,
				org_chain,
				org_merged
			}) => this.makeResponse('hierarchy', org_chain));
	}

	actionTimezone({
		workstation
	}) {
		console.log("SE TIMEZONE");

		return this.emitter.addTask('workstation', {
				_action: 'workstation-organization-data',
				workstation
			})
			.then(res => res[workstation])
			.then(({
				ws,
				org_addr,
				org_chain,
				org_merged
			}) => {
				let tm = moment.utc();
				return {
					timezone: org_merged.org_timezone,
					current_time: tm.format("x")
				};
			}).then(entities => this.makeResponse('timezone', entities));
	}

	actionPriorities({
		workstation
	}) {
		console.log("SE PRIORITIES");

		return this.emitter.addTask('workstation', {
				_action: 'workstation-organization-data',
				workstation
			})
			.then(res => res[workstation])
			.then(({
				ws,
				org_addr,
				org_chain,
				org_merged
			}) => {
				return this.iris.getGlobal('priority_description');
			})
			.then(entities => this.makeResponse('priorities', entities));
	}

	actionWorkstations({
		workstation,
		department
	}) {
		let getDepartment = _.isEmpty(department) ? this.emitter.addTask('workstation', {
			_action: 'workstation-organization-data',
			workstation
		}).then(res => res[workstation].ws.attached_to) : Promise.resolve(department);

		return getDepartment.then(res => {
				return patchwerk.get('workstation', {
					counter: '*',
					type: ['control-panel', 'terminal', 'reception'],
					department: res
				});
			})
			.then(entities => this.makeResponse('workstations', _.keyBy(entities, '@id')))
	}

	actionOperators({
		workstation,
		department
	}) {
		console.log('SE operators');
		let getDepartment = _.isEmpty(department) ? this.emitter.addTask('workstation', {
			_action: 'workstation-organization-data',
			workstation
		}).then(res => res[workstation].ws.attached_to) : Promise.resolve(department);

		return getDepartment.then(res => {
				return patchwerk.get('operator', {
					counter: '*',
					department: res
				});
			})
			.then(entities => this.makeResponse('operators', _.keyBy(entities, '@id')))
	}

	actionQaQuestions() {
		return patchwerk.get('qa-questions', {}).then(entities => this.makeResponse('questions', _.keyBy(entities, '@id')));
	}
}

module.exports = SharedEntities;
<|endoftext|>


<commit_before>var _       = require( 'lodash' );
var should  = require( 'should' );
var sinon   = require( 'sinon' );
var pequire = require( 'proxyquire' ).noCallThru();
var tutil   = require( './lib/test-util' );

var HAPPY_PROXY_DEPS = {
    gulp:            { Gulp:           _.noop },
    './hub-util':    { isValidHubFile: function (){ return true } },
    './add-subtask': _.noop
};

var getLoad = function ( proxyDeps ) {
    return pequire( '../lib/load-subfile', _.assign( {}, HAPPY_PROXY_DEPS, proxyDeps ) );
};

describe( 'load-subfile', function () {

    it( 'errors if subfile is not a valid Gulp Hub file', function () {
        var loadSubfile = getLoad( {
            './hub-util': {
                isValidHubFile: function () { return false }
            }
        } );
        loadSubfile.should.throw( '`subfile` must be a valid Gulp Hub file object.' );
    } );

    it( 'errors if the task registry is not an object', function () {
        var loadSubfile = getLoad();
        tutil.getTypeExamples( _.isPlainObject ).forEach( function ( testTasksParam ) {
            loadSubfile.bind( null, null, testTasksParam ).should.throw( '`task` must be an object' );
        } );
    } );

    xit( 'loads the specified file', function () {
        var pdeps = { 'abs-path': _.noop };
        var loadSubfile = getLoad( pdeps );
        loadSubfile( { absolutePath: 'abs-path' }, {} );
    } );
} );
<commit_msg>Stub out remaining load-subfile specs, add TODO to implement later<commit_after>var _       = require( 'lodash' );
var should  = require( 'should' );
var sinon   = require( 'sinon' );
var pequire = require( 'proxyquire' ).noCallThru();
var tutil   = require( './lib/test-util' );

var HAPPY_PROXY_DEPS = {
    gulp:            { Gulp:           _.noop },
    './hub-util':    { isValidHubFile: function (){ return true } },
    './add-subtask': _.noop
};

var getLoad = function ( proxyDeps ) {
    return pequire( '../lib/load-subfile', _.assign( {}, HAPPY_PROXY_DEPS, proxyDeps ) );
};

describe( 'load-subfile', function () {

    it( 'errors if subfile is not a valid Gulp Hub file', function () {
        var loadSubfile = getLoad( {
            './hub-util': {
                isValidHubFile: function () { return false }
            }
        } );
        loadSubfile.should.throw( '`subfile` must be a valid Gulp Hub file object.' );
    } );

    it( 'errors if the task registry is not an object', function () {
        var loadSubfile = getLoad();
        tutil.getTypeExamples( _.isPlainObject ).forEach( function ( testTasksParam ) {
            loadSubfile.bind( null, null, testTasksParam ).should.throw( '`task` must be an object' );
        } );
    } );

    // TODO: Implement these specs. I'm not sure exactly how to test these
    // specs as the current implementation involves the `require`, `module`
    // objects which are local to each script. - @robatron

    it( 'proxies `gulp.task` to our add-subtask' );

    it( '`require`s the specified file' );

    it( 'adds tasks from the local gulpfile' );
} );
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import { expect } from 'chai';
import MarkupFrame from '../src';

function mount( component ) {
	const contentArea = window.document.querySelector( '#content' );
	ReactDOM.render( component, contentArea );
}

describe( '<MarkupFrame />', function() {
	it( 'renders an iframe', function() {
		mount( <MarkupFrame markup="" /> );
		const iframes = window.document.querySelectorAll( 'iframe' );
		expect( iframes ).to.have.length( 1 );
	} );

	it( 'injects props.markup into the iframe', function() {
		mount( <MarkupFrame markup="
Hello World
" /> );
		const iframe = window.document.querySelector( 'iframe' );
		expect( iframe.contentWindow.document.body.innerHTML ).to.eql( '
Hello World
' )
	} );

	it( 'calls props.onLoad with the iframe document', function( done ) {
		const onLoad = function( doc ) {
			doc.querySelector( 'h1' ).innerHTML = 'greetings';
			const iframe = window.document.querySelector( 'iframe' );
			expect( iframe.contentWindow.document.body.innerHTML ).to.eql( '
greetings
' );
			done();
		};
		mount( <MarkupFrame markup="
Hello World
" onLoad={ onLoad } /> );
	} );
} );
<commit_msg>Add skip to failing test<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import { expect } from 'chai';
import MarkupFrame from '../src';

function mount( component ) {
	const contentArea = window.document.querySelector( '#content' );
	ReactDOM.render( component, contentArea );
}

describe( '<MarkupFrame />', function() {
	it( 'renders an iframe', function() {
		mount( <MarkupFrame markup="" /> );
		const iframes = window.document.querySelectorAll( 'iframe' );
		expect( iframes ).to.have.length( 1 );
	} );

	it( 'injects props.markup into the iframe', function() {
		mount( <MarkupFrame markup="
Hello World
" /> );
		const iframe = window.document.querySelector( 'iframe' );
		expect( iframe.contentWindow.document.body.innerHTML ).to.eql( '
Hello World
' )
	} );

	it.skip( 'calls props.onLoad with the iframe document', function( done ) {
		const onLoad = function( doc ) {
			doc.querySelector( 'h1' ).innerHTML = 'greetings';
			const iframe = window.document.querySelector( 'iframe' );
			expect( iframe.contentWindow.document.body.innerHTML ).to.eql( '
greetings
' );
			done();
		};
		mount( <MarkupFrame markup="
Hello World
" onLoad={ onLoad } /> );
	} );
} );
<|endoftext|>


<commit_before>import React from 'react';

import { string, number, func } from 'prop-types';

import styles from './styles.scss';

const Avatar = ({ src, size = 85, label, onClick }) => {
  return (
    <div
      style={{
        backgroundImage: `url(${src})`,
        height: size,
        width: size,
        cursor: onClick ? 'pointer' : 'initial'
      }}
      className={styles.container}
      onClick={onClick}
    >
      {label && (

            {label}

      )}

  );
};

Avatar.propTypes = {
  src: string.isRequired,
  size: number,
  label: string,
  onClick: func
};

export default Avatar;
<commit_msg>add proper button behavior to Avatar<commit_after>import React from 'react';
import ButtonBase from '@material-ui/core/ButtonBase';

import { string, number, func } from 'prop-types';

import styles from './styles.scss';

const Avatar = ({ src, size = 85, label, onClick }) => {
  return (
    <ButtonBase centerRipple onClick={onClick} disabled={!onClick}>
      <div
        style={{
          backgroundImage: `url(${src})`,
          height: size,
          width: size,
          cursor: onClick ? 'pointer' : 'initial'
        }}
        className={styles.container}
      >
        {label && (

              {label}

        )}

    </ButtonBase>
  );
};

Avatar.propTypes = {
  src: string.isRequired,
  size: number,
  label: string,
  onClick: func
};

export default Avatar;
<|endoftext|>


<commit_before>import React from 'react';
import { shallow, mount } from 'enzyme';
import { PlayProgressBar } from '../';

describe('PlayProgressBar', () => {
  it('should render with "div" tag', () => {
    const wrapper = mount(
      <PlayProgressBar
        currentTime={10}
        duration={1000}
      />
    );
    expect(wrapper.find('div.video-react-play-progress').length).toBe(1);
  });

  it('should render with "video-react-play-progress" class', () => {
    const wrapper = shallow(
      <PlayProgressBar
        currentTime={10}
        duration={1000}
      />
    );
    expect(wrapper.hasClass('video-react-play-progress')).toBe(true);
  });

});
<commit_msg>Adding test case of ProgressBar<commit_after>import React from 'react';
import { shallow, mount } from 'enzyme';
import { PlayProgressBar } from '../';

describe('PlayProgressBar', () => {
  it('should render with "div" tag', () => {
    const wrapper = mount(
      <PlayProgressBar
        currentTime={10}
        duration={1000}
      />
    );
    expect(wrapper.find('div.video-react-play-progress').length).toBe(1);
  });

  it('should render with "video-react-play-progress" class', () => {
    const wrapper = shallow(
      <PlayProgressBar
        currentTime={10}
        duration={1000}
      />
    );
    expect(wrapper.hasClass('video-react-play-progress')).toBe(true);
  });

  it('should render children when passed in', () => {
    const wrapper = shallow(
      <PlayProgressBar
        currentTime={10}
        duration={1000}
      />
    );
    expect(wrapper.children().length).toBeGreaterThan(0);
  });
});
<|endoftext|>


<commit_before>import PropTypes from 'prop-types'
import React from 'react'
import EventRow from '../../EventRow'
import Selection, { getBoundsForNode } from '../../Selection'
import { eventSegments } from '../../utils/eventLevels'
import { getSlotAtX, pointInBox } from '../../utils/selection'
import { dragAccessors, eventTimes } from './common'
import { DnDContext } from './DnDContext'

class WeekWrapper extends React.Component {
  static propTypes = {
    isAllDay: PropTypes.bool,
    slotMetrics: PropTypes.object.isRequired,
    accessors: PropTypes.object.isRequired,
    getters: PropTypes.object.isRequired,
    components: PropTypes.object.isRequired,
    resourceId: PropTypes.any,
    rtl: PropTypes.bool,
    localizer: PropTypes.any,
  }

  static contextType = DnDContext

  constructor(...args) {
    super(...args)
    this.state = {}
    this.ref = React.createRef()
  }

  componentDidMount() {
    this._selectable()
  }

  componentWillUnmount() {
    this._teardownSelectable()
  }

  reset() {
    if (this.state.segment) this.setState({ segment: null })
  }

  update(event, start, end) {
    const segment = eventSegments(
      { ...event, end, start, __isPreview: true },
      this.props.slotMetrics.range,
      dragAccessors,
      this.props.localizer
    )

    const { segment: lastSegment } = this.state
    if (
      lastSegment &&
      segment.span === lastSegment.span &&
      segment.left === lastSegment.left &&
      segment.right === lastSegment.right
    ) {
      return
    }
    this.setState({ segment })
  }

  handleMove = (point, bounds, draggedEvent) => {
    if (!pointInBox(bounds, point)) return this.reset()
    const event = this.context.draggable.dragAndDropAction.event || draggedEvent
    const { accessors, slotMetrics, rtl, localizer } = this.props

    const slot = getSlotAtX(bounds, point.x, rtl, slotMetrics.slots)

    const date = slotMetrics.getDateForSlot(slot)

    // Adjust the dates, but maintain the times when moving
    let { start, duration } = eventTimes(event, accessors, localizer)
    start = localizer.merge(date, start)
    const end = localizer.add(start, duration, 'milliseconds')
    // LATER: when dragging a multi-row event, only the first row is animating
    this.update(event, start, end)
  }

  handleDropFromOutside = (point, bounds) => {
    if (!this.context.draggable.onDropFromOutside) return
    const { slotMetrics, rtl, localizer } = this.props

    const slot = getSlotAtX(bounds, point.x, rtl, slotMetrics.slots)
    const start = slotMetrics.getDateForSlot(slot)

    this.context.draggable.onDropFromOutside({
      start,
      end: localizer.add(start, 1, 'day'),
      allDay: false,
    })
  }

  handleDragOverFromOutside = (point, node) => {
    if (!this.context.draggable.dragFromOutsideItem) return
    this.handleMove(point, node, this.context.draggable.dragFromOutsideItem())
  }

  handleResize(point, bounds) {
    const { event, direction } = this.context.draggable.dragAndDropAction
    const { accessors, slotMetrics, rtl, localizer } = this.props

    let { start, end } = eventTimes(event, accessors, localizer)

    const slot = getSlotAtX(bounds, point.x, rtl, slotMetrics.slots)
    const date = slotMetrics.getDateForSlot(slot)
    const cursorInRow = pointInBox(bounds, point)

    if (direction === 'RIGHT') {
      if (cursorInRow) {
        if (slotMetrics.last < start) return this.reset()
        end = localizer.add(date, 1, 'day')
      } else if (
        localizer.inRange(start, slotMetrics.first, slotMetrics.last) ||
        (bounds.bottom < point.y && +slotMetrics.first > +start)
      ) {
        end = localizer.add(slotMetrics.last, 1, 'milliseconds')
      } else {
        this.setState({ segment: null })
        return
      }
      const originalEnd = accessors.end(event)
      end = localizer.merge(end, originalEnd)
      if (localizer.lt(end, start)) {
        end = originalEnd
      }
    } else if (direction === 'LEFT') {
      if (cursorInRow) {
        if (slotMetrics.first > end) return this.reset()
        start = date
      } else if (
        localizer.inRange(end, slotMetrics.first, slotMetrics.last) ||
        (bounds.top > point.y && localizer.lt(slotMetrics.last, end))
      ) {
        start = localizer.add(slotMetrics.first, -1, 'milliseconds')
      } else {
        this.reset()
        return
      }
      const originalStart = accessors.start(event)
      start = localizer.merge(start, originalStart)
      if (localizer.gt(start, end)) {
        start = originalStart
      }
    }

    this.update(event, start, end)
  }

  _selectable = () => {
    let node = this.ref.current.closest('.rbc-month-row, .rbc-allday-cell')
    let container = node.closest('.rbc-month-view, .rbc-time-view')

    let selector = (this._selector = new Selection(() => container))

    selector.on('beforeSelect', point => {
      const { isAllDay } = this.props
      const { action } = this.context.draggable.dragAndDropAction
      const bounds = getBoundsForNode(node)
      const isInBox = pointInBox(bounds, point)
      return (
        action === 'move' || (action === 'resize' && (!isAllDay || isInBox))
      )
    })

    selector.on('selecting', box => {
      const bounds = getBoundsForNode(node)
      const { dragAndDropAction } = this.context.draggable
      if (dragAndDropAction.action === 'move') this.handleMove(box, bounds)
      if (dragAndDropAction.action === 'resize') this.handleResize(box, bounds)
    })

    selector.on('selectStart', () => this.context.draggable.onStart())

    selector.on('select', point => {
      const bounds = getBoundsForNode(node)
      if (!this.state.segment) return
      if (!pointInBox(bounds, point)) {
        this.reset()
      } else {
        this.handleInteractionEnd()
      }
    })

    selector.on('dropFromOutside', point => {
      if (!this.context.draggable.onDropFromOutside) return
      const bounds = getBoundsForNode(node)
      if (!pointInBox(bounds, point)) return
      this.handleDropFromOutside(point, bounds)
    })

    selector.on('dragOverFromOutside', point => {
      if (!this.context.draggable.dragFromOutsideItem) return
      const bounds = getBoundsForNode(node)

      this.handleDragOverFromOutside(point, bounds)
    })

    selector.on('click', () => this.context.draggable.onEnd(null))

    selector.on('reset', () => {
      this.reset()
      this.context.draggable.onEnd(null)
    })
  }

  handleInteractionEnd = () => {
    const { resourceId, isAllDay } = this.props
    const { event } = this.state.segment

    this.reset()

    this.context.draggable.onEnd({
      start: event.start,
      end: event.end,
      resourceId,
      isAllDay,
    })
  }

  _teardownSelectable = () => {
    if (!this._selector) return
    this._selector.teardown()
    this._selector = null
  }

  render() {
    const { children, accessors } = this.props

    let { segment } = this.state

    return (

        {children}

        {segment && (
          <EventRow
            {...this.props}
            selected={null}
            className="rbc-addons-dnd-drag-row"
            segments={[segment]}
            accessors={{
              ...accessors,
              ...dragAccessors,
            }}
          />
        )}

    )
  }
}

export default WeekWrapper
<commit_msg>fix: Correct DragAndDrop event resizing in 'month' view<commit_after>import PropTypes from 'prop-types'
import React from 'react'
import EventRow from '../../EventRow'
import Selection, { getBoundsForNode } from '../../Selection'
import { eventSegments } from '../../utils/eventLevels'
import { getSlotAtX, pointInBox } from '../../utils/selection'
import { dragAccessors, eventTimes } from './common'
import { DnDContext } from './DnDContext'

class WeekWrapper extends React.Component {
  static propTypes = {
    isAllDay: PropTypes.bool,
    slotMetrics: PropTypes.object.isRequired,
    accessors: PropTypes.object.isRequired,
    getters: PropTypes.object.isRequired,
    components: PropTypes.object.isRequired,
    resourceId: PropTypes.any,
    rtl: PropTypes.bool,
    localizer: PropTypes.any,
  }

  static contextType = DnDContext

  constructor(...args) {
    super(...args)
    this.state = {}
    this.ref = React.createRef()
  }

  componentDidMount() {
    this._selectable()
  }

  componentWillUnmount() {
    this._teardownSelectable()
  }

  reset() {
    if (this.state.segment) this.setState({ segment: null })
  }

  update(event, start, end) {
    const segment = eventSegments(
      { ...event, end, start, __isPreview: true },
      this.props.slotMetrics.range,
      dragAccessors,
      this.props.localizer
    )

    const { segment: lastSegment } = this.state
    if (
      lastSegment &&
      segment.span === lastSegment.span &&
      segment.left === lastSegment.left &&
      segment.right === lastSegment.right
    ) {
      return
    }
    this.setState({ segment })
  }

  handleMove = (point, bounds, draggedEvent) => {
    if (!pointInBox(bounds, point)) return this.reset()
    const event = this.context.draggable.dragAndDropAction.event || draggedEvent
    const { accessors, slotMetrics, rtl, localizer } = this.props

    const slot = getSlotAtX(bounds, point.x, rtl, slotMetrics.slots)

    const date = slotMetrics.getDateForSlot(slot)

    // Adjust the dates, but maintain the times when moving
    let { start, duration } = eventTimes(event, accessors, localizer)
    start = localizer.merge(date, start)
    const end = localizer.add(start, duration, 'milliseconds')
    // LATER: when dragging a multi-row event, only the first row is animating
    this.update(event, start, end)
  }

  handleDropFromOutside = (point, bounds) => {
    if (!this.context.draggable.onDropFromOutside) return
    const { slotMetrics, rtl, localizer } = this.props

    const slot = getSlotAtX(bounds, point.x, rtl, slotMetrics.slots)
    const start = slotMetrics.getDateForSlot(slot)

    this.context.draggable.onDropFromOutside({
      start,
      end: localizer.add(start, 1, 'day'),
      allDay: false,
    })
  }

  handleDragOverFromOutside = (point, node) => {
    if (!this.context.draggable.dragFromOutsideItem) return
    this.handleMove(point, node, this.context.draggable.dragFromOutsideItem())
  }

  handleResize(point, bounds) {
    const { event, direction } = this.context.draggable.dragAndDropAction
    const { accessors, slotMetrics, rtl, localizer } = this.props

    let { start, end } = eventTimes(event, accessors, localizer)

    const slot = getSlotAtX(bounds, point.x, rtl, slotMetrics.slots)
    const date = slotMetrics.getDateForSlot(slot)
    const cursorInRow = pointInBox(bounds, point)

    if (direction === 'RIGHT') {
      if (cursorInRow) {
        if (slotMetrics.last < start) return this.reset()
        if (localizer.eq(localizer.startOf(end, 'day'), end))
          end = localizer.add(date, 1, 'day')
        else end = date
      } else if (
        localizer.inRange(start, slotMetrics.first, slotMetrics.last) ||
        (bounds.bottom < point.y && +slotMetrics.first > +start)
      ) {
        end = localizer.add(slotMetrics.last, 1, 'milliseconds')
      } else {
        this.setState({ segment: null })
        return
      }
      const originalEnd = accessors.end(event)
      end = localizer.merge(end, originalEnd)
      if (localizer.lt(end, start)) {
        end = originalEnd
      }
    } else if (direction === 'LEFT') {
      if (cursorInRow) {
        if (slotMetrics.first > end) return this.reset()
        start = date
      } else if (
        localizer.inRange(end, slotMetrics.first, slotMetrics.last) ||
        (bounds.top > point.y && localizer.lt(slotMetrics.last, end))
      ) {
        start = localizer.add(slotMetrics.first, -1, 'milliseconds')
      } else {
        this.reset()
        return
      }
      const originalStart = accessors.start(event)
      start = localizer.merge(start, originalStart)
      if (localizer.gt(start, end)) {
        start = originalStart
      }
    }

    this.update(event, start, end)
  }

  _selectable = () => {
    let node = this.ref.current.closest('.rbc-month-row, .rbc-allday-cell')
    let container = node.closest('.rbc-month-view, .rbc-time-view')

    let selector = (this._selector = new Selection(() => container))

    selector.on('beforeSelect', point => {
      const { isAllDay } = this.props
      const { action } = this.context.draggable.dragAndDropAction
      const bounds = getBoundsForNode(node)
      const isInBox = pointInBox(bounds, point)
      return (
        action === 'move' || (action === 'resize' && (!isAllDay || isInBox))
      )
    })

    selector.on('selecting', box => {
      const bounds = getBoundsForNode(node)
      const { dragAndDropAction } = this.context.draggable
      if (dragAndDropAction.action === 'move') this.handleMove(box, bounds)
      if (dragAndDropAction.action === 'resize') this.handleResize(box, bounds)
    })

    selector.on('selectStart', () => this.context.draggable.onStart())

    selector.on('select', point => {
      const bounds = getBoundsForNode(node)
      if (!this.state.segment) return
      if (!pointInBox(bounds, point)) {
        this.reset()
      } else {
        this.handleInteractionEnd()
      }
    })

    selector.on('dropFromOutside', point => {
      if (!this.context.draggable.onDropFromOutside) return
      const bounds = getBoundsForNode(node)
      if (!pointInBox(bounds, point)) return
      this.handleDropFromOutside(point, bounds)
    })

    selector.on('dragOverFromOutside', point => {
      if (!this.context.draggable.dragFromOutsideItem) return
      const bounds = getBoundsForNode(node)

      this.handleDragOverFromOutside(point, bounds)
    })

    selector.on('click', () => this.context.draggable.onEnd(null))

    selector.on('reset', () => {
      this.reset()
      this.context.draggable.onEnd(null)
    })
  }

  handleInteractionEnd = () => {
    const { resourceId, isAllDay } = this.props
    const { event } = this.state.segment

    this.reset()

    this.context.draggable.onEnd({
      start: event.start,
      end: event.end,
      resourceId,
      isAllDay,
    })
  }

  _teardownSelectable = () => {
    if (!this._selector) return
    this._selector.teardown()
    this._selector = null
  }

  render() {
    const { children, accessors } = this.props

    let { segment } = this.state

    return (

        {children}

        {segment && (
          <EventRow
            {...this.props}
            selected={null}
            className="rbc-addons-dnd-drag-row"
            segments={[segment]}
            accessors={{
              ...accessors,
              ...dragAccessors,
            }}
          />
        )}

    )
  }
}

export default WeekWrapper
<|endoftext|>


<commit_before>define(['js/core/Component'], function(Component) {

    return Component.inherit('srv.core.Interceptor', {

    });
});<commit_msg>removed Interceptor because we use Filter<commit_after><|endoftext|>


<commit_before>import mongodb from 'mongodb'
const {ObjectID} = mongodb;
import {Json2Bson} from './helper';

class MongoDataBase {
  constructor(url) {
    mongodb.MongoClient.connect(url, (err, database) => {
      this.database = database
    });
  }

  async insert(collection, newObj) {
    let result = await this.database.collection(collection).insertOne(Json2Bson(newObj));
    return result.ops[0];
  }

  async find(collection, {query,pageSize,currentPage,orderBy}) {
    query = query ? query : {};
    pageSize = pageSize ? pageSize : 10;
    currentPage = currentPage ? currentPage : 0;
    let result = await this.database.collection(collection).find(
      query,
      undefined,
      {
        limit: pageSize,
        skip: currentPage * pageSize
      }
    ).toArray();
    console.log(result.length);
    return result;
  }

  async findOne(collection, query) {
    const result = await this.database.collection(collection).findOne(Json2Bson(query));
    if (result){
      for(let name in result){
        if (result[name].constructor){
          switch (result[name].constructor.name){
            case 'ObjectID':
              result[name] = result[name].toString();
              break;
          }
        }
      }
    }
    return result;
  }

  async update(collection, query, options) {
    query = Json2Bson(query);
    options = Json2Bson(options);

    const data = await this.database.collection(collection).findOne(query);
    if (data) {
      await this.database.collection(collection).updateOne(
        query,
        options
      );
      return await this.findOne(collection, {_id: data._id});
    }
    return null;
  }

  async 'delete'(collection, query) {
    const result = await this.database.collection(collection).findOne(query);
    if (result){
      await this.database.collection(collection).deleteOne(query);
    }
    return result;
  }
}
export default MongoDataBase<commit_msg>sidebar，操作记录<commit_after>import mongodb from 'mongodb'
const {ObjectID} = mongodb;
import {Json2Bson} from './helper';

class MongoDataBase {
  constructor(url) {
    mongodb.MongoClient.connect(url, (err, database) => {
      this.database = database
    });
  }

  async insert(collection, newObj) {
    let result = await this.database.collection(collection).insertOne(Json2Bson(newObj));
    return result.ops[0];
  }

  async find(collection, {query,pageSize,currentPage,orderBy}) {
    query = query ? query : {};
    pageSize = pageSize ? pageSize : 10;
    currentPage = currentPage ? currentPage : 0;
    let result = await this.database.collection(collection).find(
      query,
      undefined,
      {
        limit: pageSize,
        skip: currentPage * pageSize
      }
    ).toArray();
    return result;
  }

  async findOne(collection, query) {
    const result = await this.database.collection(collection).findOne(Json2Bson(query));
    if (result){
      for(let name in result){
        if (result[name].constructor){
          switch (result[name].constructor.name){
            case 'ObjectID':
              result[name] = result[name].toString();
              break;
          }
        }
      }
    }
    return result;
  }

  async update(collection, query, options) {
    query = Json2Bson(query);
    options = Json2Bson(options);

    const data = await this.database.collection(collection).findOne(query);
    if (data) {
      await this.database.collection(collection).updateOne(
        query,
        options
      );
      return await this.findOne(collection, {_id: data._id});
    }
    return null;
  }

  async 'delete'(collection, query) {
    const result = await this.database.collection(collection).findOne(query);
    if (result){
      await this.database.collection(collection).deleteOne(query);
    }
    return result;
  }
}
export default MongoDataBase<|endoftext|>


<commit_before>import React from "react";

import {
  Summary,
  Results,
  Paginator,
  ImageResult,
  Result
} from "sajari-react/ui/results";
import { TabsFacet } from "sajari-react/ui/facets";
import { responseUpdatedEvent } from "sajari-react/controllers";

import { values, pipeline, tracking } from "./resources";

class SearchResponse extends React.Component {
  constructor(props) {
    super(props);

    this.state = { response: pipeline.getResponse() };
  }

  componentDidMount() {
    this.removeResponseListener = pipeline.listen(
      responseUpdatedEvent,
      this.responseUpdated
    );
  }

  componentWillUnmount() {
    this.removeResponseListener();
  }

  responseUpdated = () => {
    this.setState({ response: pipeline.getResponse() });
  };

  render() {
    const { config, tabsFilter } = this.props;
    const { results } = this.state;

    if ((!results.time && !pipeline.getError()) || !values.get().q) {
      return null;
    }

    let tabs = null;
    if (config.tabFilters) {
      const tabsFacetMap = config.tabFilters.tabs.map(t => ({
        name: t.title,
        displayText: t.title
      }));
      tabs = <TabsFacet tabs={tabsFacetMap} filter={tabsFilter} />;
    }

    const resultsConfig = config.results || {};
    const resultRenderer = resultsConfig.showImages ? ImageResult : Result;
    return (

        {tabs}

        <Results
          ResultRenderer={resultRenderer}
          values={values}
          pipeline={pipeline}
        />
        <Paginator values={values} pipeline={pipeline} tracking={tracking} />

    );
  }
}

export default SearchResponse;
<commit_msg>site-search: use new response in SearchRespone<commit_after>import React from "react";

import {
  Summary,
  Results,
  Paginator,
  ImageResult,
  Result
} from "sajari-react/ui/results";
import { TabsFacet } from "sajari-react/ui/facets";
import { responseUpdatedEvent } from "sajari-react/controllers";

import { values, pipeline, tracking } from "./resources";

class SearchResponse extends React.Component {
  constructor(props) {
    super(props);

    this.state = { response: pipeline.getResponse() };
  }

  componentDidMount() {
    this.removeResponseListener = pipeline.listen(
      responseUpdatedEvent,
      this.responseUpdated
    );
  }

  componentWillUnmount() {
    this.removeResponseListener();
  }

  responseUpdated = () => {
    this.setState({ response: pipeline.getResponse() });
  };

  render() {
    const { config, tabsFilter } = this.props;
    const { response } = this.state;

    if (response.isEmpty() || !response.getQueryValues().q) {
      return null;
    }

    let tabs = null;
    if (config.tabFilters) {
      const tabsFacetMap = config.tabFilters.tabs.map(t => ({
        name: t.title,
        displayText: t.title
      }));
      tabs = <TabsFacet tabs={tabsFacetMap} filter={tabsFilter} />;
    }

    const resultsConfig = config.results || {};
    const resultRenderer = resultsConfig.showImages ? ImageResult : Result;
    return (

        {tabs}

        <Results
          ResultRenderer={resultRenderer}
          values={values}
          pipeline={pipeline}
        />
        <Paginator values={values} pipeline={pipeline} tracking={tracking} />

    );
  }
}

export default SearchResponse;
<|endoftext|>