<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

const React = require('react')
const urlParse = require('url').parse
const WindowActions = require('../actions/windowActions')
const AppActions = require('../actions/appActions')
const ImmutableComponent = require('./immutableComponent')
const Immutable = require('immutable')
const cx = require('../lib/classSet.js')
const UrlUtil = require('./../../node_modules/urlutil.js/dist/node-urlutil.js')
const messages = require('../constants/messages.js')
const remote = global.require('electron').remote

import adInfo from '../data/adInfo.js'
import Config from '../constants/config.js'
import FindBar from './findbar.js'
import { isSourceAboutUrl, getTargetAboutUrl } from '../lib/appUrlUtil.js'

class Frame extends ImmutableComponent {
  constructor () {
    super()
  }

  updateWebview () {
    let src = this.props.frame.get('src')
    const isAboutURL = isSourceAboutUrl(src)
    if (isAboutURL) {
      src = getTargetAboutUrl(src)
    }
    let contentScripts = ['content/webviewPreload.js']
    if (this.props.frame.get('location') === 'about:preferences') {
      contentScripts.push('content/aboutPreload.js')
    }
    contentScripts = contentScripts.join(',')

    const contentScriptsChanged =
      this.webview && contentScripts !== this.webview.getAttribute('contentScripts')

    // Create the webview dynamically because React doesn't whitelist all
    // of the attributes we need.  Clear out old webviews if the contentScripts
    // change because they cannot change after being added to the DOM.
    if (contentScriptsChanged) {
      while (this.webviewContainer.firstChild) {
        this.webviewContainer.removeChild(this.webviewContainer.firstChild)
      }
    }
    this.webview = !contentScriptsChanged && this.webview || document.createElement('webview')
    this.webview.setAttribute('allowDisplayingInsecureContent', true)
    this.webview.setAttribute('data-frame-key', this.props.frame.get('key'))
    this.webview.setAttribute('contentScripts', contentScripts)
    if (this.props.frame.get('isPrivate')) {
      this.webview.setAttribute('partition', 'private-1')
    } else if (this.props.frame.get('partitionNumber')) {
      this.webview.setAttribute('partition', `persist:partition-${this.props.frame.get('partitionNumber')}`)
    }
    if (this.props.frame.get('guestInstanceId')) {
      this.webview.setAttribute('data-guest-instance-id', this.props.frame.get('guestInstanceId'))
    }
    this.webview.setAttribute('src', src)
    if (!this.webviewContainer.firstChild) {
      this.webviewContainer.appendChild(this.webview)
      this.addEventListeners()
    }
  }

  componentDidMount () {
    this.updateWebview()
  }

  componentDidUpdate (prevProps, prevState) {
    const didSrcChange = this.props.frame.get('src') !== prevProps.frame.get('src')
    if (didSrcChange) {
      this.updateWebview()
    }
    // give focus when switching tabs
    if (this.props.isActive && !prevProps.isActive) {
      this.webview.focus()
    }
    const activeShortcut = this.props.frame.get('activeShortcut')
    switch (activeShortcut) {
      case 'stop':
        this.webview.stop()
        break
      case 'reload':
        if (this.props.frame.get('location') === 'about:preferences') {
          break
        }
        this.webview.reload()
        break
      case 'clean-reload':
        this.webview.reloadIgnoringCache()
        break
      case 'zoom-in':
        WindowActions.zoomIn(this.props.frame)
        break
      case 'zoom-out':
        WindowActions.zoomOut(this.props.frame)
        break
      case 'zoom-reset':
        WindowActions.zoomReset(this.props.frame)
        break
      case 'toggle-dev-tools':
        if (this.webview.isDevToolsOpened()) {
          this.webview.closeDevTools()
        } else {
          this.webview.openDevTools()
        }
        break
      case 'view-source':
        const src = UrlUtil.getViewSourceUrlFromUrl(this.webview.getURL())
        WindowActions.loadUrl(this.props.frame, src)
        // TODO: Make the URL bar show the view-source: prefix
        WindowActions.setFrameTitle(this.props.frame, src)
        break
      case 'save':
        // TODO: Sometimes this tries to save in a non-existent directory
        this.webview.downloadURL(this.webview.getURL())
        break
      case 'print':
        this.webview.print()
        break
      case 'show-findbar':
        WindowActions.setFindbarShown(this.props.frame, true)
        break
    }
    if (activeShortcut) {
      WindowActions.setActiveFrameShortcut(null)
    }

    if (this.props.frame.get('location') === 'about:preferences') {
      this.webview.send(messages.SETTINGS_UPDATED, this.props.settings.toJS())
    }
  }

  addEventListeners () {
    this.webview.addEventListener('focus', this.onFocus.bind(this))
    // @see <a href="https://github.com/atom/electron/blob/master/docs/api/web-view-tag.md#event-new-window">new-window event</a>
    this.webview.addEventListener('new-window', (e, url, frameName, disposition, options) => {
      e.preventDefault()

      const guestInstanceId = e.options && e.options.webPreferences && e.options.webPreferences.guestInstanceId
      const windowOptions = e.options && e.options.windowOptions || {}
      windowOptions.parentWindowKey = remote.getCurrentWindow().id
      windowOptions.disposition = e.disposition

      if (e.disposition === 'new-window' || e.disposition === 'new-popup') {
        AppActions.newWindow({
          location: e.url,
          parentFrameKey: this.props.frame.get('key'),
          isPrivate: this.props.frame.get('isPrivate'),
          partitionNumber: this.props.frame.get('partitionNumber'),
          guestInstanceId
        }, windowOptions)
      } else {
        const openInForeground = this.props.prefOpenInForeground === true ||
          e.disposition !== 'background-tab'
        WindowActions.newFrame({
          location: e.url,
          parentFrameKey: this.props.frame.get('key'),
          isPrivate: this.props.frame.get('isPrivate'),
          partitionNumber: this.props.frame.get('partitionNumber'),
          guestInstanceId
        }, openInForeground)
      }
    })
    this.webview.addEventListener('destroyed', (e) => {
      this.props.onCloseFrame(this.props.frame)
    })
    this.webview.addEventListener('close', () => {
      AppActions.closeWindow(remote.getCurrentWindow().id)
    })
    this.webview.addEventListener('enter-html-full-screen', () => {
    })
    this.webview.addEventListener('leave-html-full-screen', () => {
    })
    this.webview.addEventListener('page-favicon-updated', (e) => {
      if (e.favicons && e.favicons.length > 0) {
        WindowActions.setFavicon(this.props.frame, e.favicons[0])
      }
    })
    this.webview.addEventListener('page-title-set', ({title}) => {
      WindowActions.setFrameTitle(this.props.frame, title)
    })
    this.webview.addEventListener('dom-ready', (event) => {
      if (this.props.enableAds) {
        this.insertAds(event.target.src)
      }
    })
    const frame = this.props.frame
    this.webview.addEventListener('ipc-message', (e) => {
      let action = e.channel
      switch (action.actionType) {<commit_msg>only close the tab when the webview is closed<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

const React = require('react')
const urlParse = require('url').parse
const WindowActions = require('../actions/windowActions')
const AppActions = require('../actions/appActions')
const ImmutableComponent = require('./immutableComponent')
const Immutable = require('immutable')
const cx = require('../lib/classSet.js')
const UrlUtil = require('./../../node_modules/urlutil.js/dist/node-urlutil.js')
const messages = require('../constants/messages.js')
const remote = global.require('electron').remote

import adInfo from '../data/adInfo.js'
import Config from '../constants/config.js'
import FindBar from './findbar.js'
import { isSourceAboutUrl, getTargetAboutUrl } from '../lib/appUrlUtil.js'

class Frame extends ImmutableComponent {
  constructor () {
    super()
  }

  updateWebview () {
    let src = this.props.frame.get('src')
    const isAboutURL = isSourceAboutUrl(src)
    if (isAboutURL) {
      src = getTargetAboutUrl(src)
    }
    let contentScripts = ['content/webviewPreload.js']
    if (this.props.frame.get('location') === 'about:preferences') {
      contentScripts.push('content/aboutPreload.js')
    }
    contentScripts = contentScripts.join(',')

    const contentScriptsChanged =
      this.webview && contentScripts !== this.webview.getAttribute('contentScripts')

    // Create the webview dynamically because React doesn't whitelist all
    // of the attributes we need.  Clear out old webviews if the contentScripts
    // change because they cannot change after being added to the DOM.
    if (contentScriptsChanged) {
      while (this.webviewContainer.firstChild) {
        this.webviewContainer.removeChild(this.webviewContainer.firstChild)
      }
    }
    this.webview = !contentScriptsChanged && this.webview || document.createElement('webview')
    this.webview.setAttribute('allowDisplayingInsecureContent', true)
    this.webview.setAttribute('data-frame-key', this.props.frame.get('key'))
    this.webview.setAttribute('contentScripts', contentScripts)
    if (this.props.frame.get('isPrivate')) {
      this.webview.setAttribute('partition', 'private-1')
    } else if (this.props.frame.get('partitionNumber')) {
      this.webview.setAttribute('partition', `persist:partition-${this.props.frame.get('partitionNumber')}`)
    }
    if (this.props.frame.get('guestInstanceId')) {
      this.webview.setAttribute('data-guest-instance-id', this.props.frame.get('guestInstanceId'))
    }
    this.webview.setAttribute('src', src)
    if (!this.webviewContainer.firstChild) {
      this.webviewContainer.appendChild(this.webview)
      this.addEventListeners()
    }
  }

  componentDidMount () {
    this.updateWebview()
  }

  componentDidUpdate (prevProps, prevState) {
    const didSrcChange = this.props.frame.get('src') !== prevProps.frame.get('src')
    if (didSrcChange) {
      this.updateWebview()
    }
    // give focus when switching tabs
    if (this.props.isActive && !prevProps.isActive) {
      this.webview.focus()
    }
    const activeShortcut = this.props.frame.get('activeShortcut')
    switch (activeShortcut) {
      case 'stop':
        this.webview.stop()
        break
      case 'reload':
        if (this.props.frame.get('location') === 'about:preferences') {
          break
        }
        this.webview.reload()
        break
      case 'clean-reload':
        this.webview.reloadIgnoringCache()
        break
      case 'zoom-in':
        WindowActions.zoomIn(this.props.frame)
        break
      case 'zoom-out':
        WindowActions.zoomOut(this.props.frame)
        break
      case 'zoom-reset':
        WindowActions.zoomReset(this.props.frame)
        break
      case 'toggle-dev-tools':
        if (this.webview.isDevToolsOpened()) {
          this.webview.closeDevTools()
        } else {
          this.webview.openDevTools()
        }
        break
      case 'view-source':
        const src = UrlUtil.getViewSourceUrlFromUrl(this.webview.getURL())
        WindowActions.loadUrl(this.props.frame, src)
        // TODO: Make the URL bar show the view-source: prefix
        WindowActions.setFrameTitle(this.props.frame, src)
        break
      case 'save':
        // TODO: Sometimes this tries to save in a non-existent directory
        this.webview.downloadURL(this.webview.getURL())
        break
      case 'print':
        this.webview.print()
        break
      case 'show-findbar':
        WindowActions.setFindbarShown(this.props.frame, true)
        break
    }
    if (activeShortcut) {
      WindowActions.setActiveFrameShortcut(null)
    }

    if (this.props.frame.get('location') === 'about:preferences') {
      this.webview.send(messages.SETTINGS_UPDATED, this.props.settings.toJS())
    }
  }

  addEventListeners () {
    this.webview.addEventListener('focus', this.onFocus.bind(this))
    // @see <a href="https://github.com/atom/electron/blob/master/docs/api/web-view-tag.md#event-new-window">new-window event</a>
    this.webview.addEventListener('new-window', (e, url, frameName, disposition, options) => {
      e.preventDefault()

      const guestInstanceId = e.options && e.options.webPreferences && e.options.webPreferences.guestInstanceId
      const windowOptions = e.options && e.options.windowOptions || {}
      windowOptions.disposition = e.disposition

      if (e.disposition === 'new-window' || e.disposition === 'new-popup') {
        AppActions.newWindow({
          location: e.url,
          parentFrameKey: this.props.frame.get('key'),
          isPrivate: this.props.frame.get('isPrivate'),
          partitionNumber: this.props.frame.get('partitionNumber'),
          guestInstanceId
        }, windowOptions)
      } else {
        const openInForeground = this.props.prefOpenInForeground === true ||
          e.disposition !== 'background-tab'
        WindowActions.newFrame({
          location: e.url,
          parentFrameKey: this.props.frame.get('key'),
          isPrivate: this.props.frame.get('isPrivate'),
          partitionNumber: this.props.frame.get('partitionNumber'),
          guestInstanceId
        }, openInForeground)
      }
    })
    this.webview.addEventListener('destroyed', (e) => {
      this.props.onCloseFrame(this.props.frame)
    })
    this.webview.addEventListener('close', () => {
      WindowActions.closeFrame(this.props.frames, this.props.frame)
    })
    this.webview.addEventListener('enter-html-full-screen', () => {
    })
    this.webview.addEventListener('leave-html-full-screen', () => {
    })
    this.webview.addEventListener('page-favicon-updated', (e) => {
      if (e.favicons && e.favicons.length > 0) {
        WindowActions.setFavicon(this.props.frame, e.favicons[0])
      }
    })
    this.webview.addEventListener('page-title-set', ({title}) => {
      WindowActions.setFrameTitle(this.props.frame, title)
    })
    this.webview.addEventListener('dom-ready', (event) => {
      if (this.props.enableAds) {
        this.insertAds(event.target.src)
      }
    })
    const frame = this.props.frame
    this.webview.addEventListener('ipc-message', (e) => {
      let action = e.channel
      switch (action.actionType) {
{'fraction_non_alphanumeric': 0.13718191662154847, 'fraction_numerical': 0.0009474824038982133, 'mean_word_length': 2.976587728740581, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 27, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6777372', 'n_tokens_mistral': 4382, 'n_tokens_neox': 4367, 'n_words': 781}