<commit_before>// Theirs
import React from 'react'
import HTML5Backend from 'react-dnd-html5-backend'
import { DragDropContext } from 'react-dnd'
import domtoimage from 'dom-to-image'
import ReadFileDropContainer, { DATA_URL, TEXT } from 'dropperx'
import Spinner from 'react-spinner'

// Ours
import Button from './Button'
import Dropdown from './Dropdown'
import BackgroundSelect from './BackgroundSelect'
import Settings from './Settings'
import Toolbar from './Toolbar'
import Overlay from './Overlay'
import Carbon from './Carbon'
import api from '../lib/api'
import {
  THEMES,
  THEMES_HASH,
  LANGUAGES,
  LANGUAGE_MIME_HASH,
  LANGUAGE_MODE_HASH,
  LANGUAGE_NAME_HASH,
  DEFAULT_THEME,
  DEFAULT_EXPORT_SIZE,
  COLORS,
  EXPORT_SIZES_HASH,
  DEFAULT_CODE,
  DEFAULT_SETTINGS
} from '../lib/constants'
import { serializeState } from '../lib/routing'
import { getState } from '../lib/util'

const saveButtonOptions = {
  button: true,
  color: '#c198fb',
  selected: { id: 'SAVE_IMAGE', name: 'Save Image' },
  list: ['png', 'svg', 'open ↗'].map(id => ({ id, name: id.toUpperCase() }))
}

class Editor extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      ...DEFAULT_SETTINGS,
      loading: true,
      uploading: false,
      code: props.content,
      online: true
    }

    this.save = this.save.bind(this)
    this.upload = this.upload.bind(this)
    this.updateSetting = this.updateSetting.bind(this)
    this.updateCode = this.updateSetting.bind(this, 'code')
    this.updateAspectRatio = this.updateSetting.bind(this, 'aspectRatio')
    this.updateTitleBar = this.updateSetting.bind(this, 'titleBar')
    this.updateTheme = this.updateTheme.bind(this)
    this.updateLanguage = this.updateLanguage.bind(this)
    this.updateBackground = this.updateBackground.bind(this)
    this.resetDefaultSettings = this.resetDefaultSettings.bind(this)
    this.getCarbonImage = this.getCarbonImage.bind(this)
    this.onDrop = this.onDrop.bind(this)

    this.setOffline = () => this.setState({ online: false })
    this.setOnline = () => this.setState({ online: true })
  }

  componentDidMount() {
    // Load from localStorage and then URL params
    this.setState({
      ...getState(localStorage),
      ...this.props.initialState,
      loading: false,
      online: Boolean(window && window.navigator && window.navigator.onLine)
    })

    window.addEventListener('offline', this.setOffline);
    window.addEventListener('online', this.setOnline);
  }

  componentWillUnmount() {
    window.removeEventListener('offline', this.setOffline);
    window.removeEventListener('online', this.setOnline);
  }

  componentDidUpdate() {
    this.props.onUpdate(this.state)
  }

  getCarbonImage({ format, type } = { format: 'png' }) {
    // if safari, get image from api
    if (
      navigator.userAgent.indexOf('Safari') !== -1 &&
      navigator.userAgent.indexOf('Chrome') === -1 &&
      format !== 'svg'
    ) {
      const encodedState = serializeState(this.state)
      return api.image(encodedState)
    }

    const node = document.getElementById('export-container')

    const exportSize = (EXPORT_SIZES_HASH[this.state.exportSize] || DEFAULT_EXPORT_SIZE).value
    const width = node.offsetWidth * exportSize
    const height = this.state.squaredImage
      ? node.offsetWidth * exportSize
      : node.offsetHeight * exportSize

    const config = {
      style: {
        transform: `scale(${exportSize})`,
        'transform-origin': 'center',
        background: this.state.squaredImage ? this.state.backgroundColor : 'none'
      },
      filter: n => {
        // %[00 -> 19] cause failures
        if (
          n.innerText && n.innerText.match(/%\S\S/) &&
          n.className &&
          n.className.startsWith('cm-') && // is CodeMirror primitive string
          format === 'png' // only occurs when saving PNG
        ) {
          n.innerText = encodeURIComponent(n.innerText)
        }
        if (n.className) {
          return String(n.className).indexOf('eliminateOnRender') < 0
        }
        return true
      },
      width,
      height
    }

    if (type === 'blob') {
      if (format === 'svg') {<commit_msg>encode text before reading the container width (#466)<commit_after>// Theirs
import React from 'react'
import HTML5Backend from 'react-dnd-html5-backend'
import { DragDropContext } from 'react-dnd'
import domtoimage from 'dom-to-image'
import ReadFileDropContainer, { DATA_URL, TEXT } from 'dropperx'
import Spinner from 'react-spinner'

// Ours
import Button from './Button'
import Dropdown from './Dropdown'
import BackgroundSelect from './BackgroundSelect'
import Settings from './Settings'
import Toolbar from './Toolbar'
import Overlay from './Overlay'
import Carbon from './Carbon'
import api from '../lib/api'
import {
  THEMES,
  THEMES_HASH,
  LANGUAGES,
  LANGUAGE_MIME_HASH,
  LANGUAGE_MODE_HASH,
  LANGUAGE_NAME_HASH,
  DEFAULT_THEME,
  DEFAULT_EXPORT_SIZE,
  COLORS,
  EXPORT_SIZES_HASH,
  DEFAULT_CODE,
  DEFAULT_SETTINGS
} from '../lib/constants'
import { serializeState } from '../lib/routing'
import { getState } from '../lib/util'

const saveButtonOptions = {
  button: true,
  color: '#c198fb',
  selected: { id: 'SAVE_IMAGE', name: 'Save Image' },
  list: ['png', 'svg', 'open ↗'].map(id => ({ id, name: id.toUpperCase() }))
}

class Editor extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      ...DEFAULT_SETTINGS,
      loading: true,
      uploading: false,
      code: props.content,
      online: true
    }

    this.save = this.save.bind(this)
    this.upload = this.upload.bind(this)
    this.updateSetting = this.updateSetting.bind(this)
    this.updateCode = this.updateSetting.bind(this, 'code')
    this.updateAspectRatio = this.updateSetting.bind(this, 'aspectRatio')
    this.updateTitleBar = this.updateSetting.bind(this, 'titleBar')
    this.updateTheme = this.updateTheme.bind(this)
    this.updateLanguage = this.updateLanguage.bind(this)
    this.updateBackground = this.updateBackground.bind(this)
    this.resetDefaultSettings = this.resetDefaultSettings.bind(this)
    this.getCarbonImage = this.getCarbonImage.bind(this)
    this.onDrop = this.onDrop.bind(this)

    this.setOffline = () => this.setState({ online: false })
    this.setOnline = () => this.setState({ online: true })
  }

  componentDidMount() {
    // Load from localStorage and then URL params
    this.setState({
      ...getState(localStorage),
      ...this.props.initialState,
      loading: false,
      online: Boolean(window && window.navigator && window.navigator.onLine)
    })

    window.addEventListener('offline', this.setOffline);
    window.addEventListener('online', this.setOnline);
  }

  componentWillUnmount() {
    window.removeEventListener('offline', this.setOffline);
    window.removeEventListener('online', this.setOnline);
  }

  componentDidUpdate() {
    this.props.onUpdate(this.state)
  }

  getCarbonImage({ format, type } = { format: 'png' }) {
    // if safari, get image from api
    const isPNG = format !== 'svg'
    if (
      navigator.userAgent.indexOf('Safari') !== -1 &&
      navigator.userAgent.indexOf('Chrome') === -1 &&
      isPNG
    ) {
      const encodedState = serializeState(this.state)
      return api.image(encodedState)
    }

    if (isPNG) {
      document.querySelectorAll('.CodeMirror-line > span > span').forEach(n => {
        if (n.innerText && n.innerText.match(/%\S\S/)) {
          n.innerText = encodeURIComponent(n.innerText);
        }
      })
    }

    const node = document.getElementById('export-container')

    const exportSize = (EXPORT_SIZES_HASH[this.state.exportSize] || DEFAULT_EXPORT_SIZE).value
    const width = node.offsetWidth * exportSize
    const height = this.state.squaredImage
      ? node.offsetWidth * exportSize
      : node.offsetHeight * exportSize

    const config = {
      style: {
        transform: `scale(${exportSize})`,
        'transform-origin': 'center',
        background: this.state.squaredImage ? this.state.backgroundColor : 'none'
      },
      filter: n => {
        if (n.className) {
          return String(n.className).indexOf('eliminateOnRender') < 0
        }
        return true
      },
      width,
      height
    }

    if (type === 'blob') {
      if (format === 'svg') {
{'fraction_non_alphanumeric': 0.1338686481303931, 'fraction_numerical': 0.00275647171620326, 'mean_word_length': 3.1209876543209876, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '617026', 'n_tokens_mistral': 2630, 'n_tokens_neox': 2584, 'n_words': 546}