<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 Immutable = require('immutable')

// Components
const ImmutableComponent = require('../../immutableComponent')

// Actions
const windowActions = require('../../../../../js/actions/windowActions')

// Utils
const cx = require('../../../../../js/lib/classSet')
const {formatAccelerator} = require('../../../../common/lib/formatUtil')

class ContextMenuItem extends ImmutableComponent {
  componentDidMount () {
    if (this.node) {
      this.node.addEventListener('auxclick', this.onAuxClick.bind(this))
    }
  }
  get submenu () {
    return this.props.contextMenuItem.get('submenu')
  }
  get items () {
    return this.props.contextMenuItem.get('items')
  }
  get hasSubmenu () {
    return this.submenu && this.submenu.size > 0
  }
  get isMulti () {
    return this.items && this.items.size > 0
  }

  get accelerator () {
    const accelerator = this.props.contextMenuItem.get('accelerator')
    return accelerator && typeof accelerator === 'string'
      ? accelerator.trim()
      : null
  }
  get hasAccelerator () {
    return this.accelerator !== null
  }
  onClick (clickAction, shouldHide, e) {
    e.stopPropagation()
    if (clickAction) {
      if (shouldHide) {
        setImmediate(() => windowActions.resetMenuState())
      }
      clickAction(e)
    }
  }
  onDragStart (e) {
    if (this.props.contextMenuItem.get('dragStart')) {
      this.props.contextMenuItem.get('dragStart')(e)
    }
  }
  onDragEnd (e) {
    if (this.props.contextMenuItem.get('dragEnd')) {
      this.props.contextMenuItem.get('dragEnd')(e)
    }
  }
  onDragOver (e) {
    if (this.props.contextMenuItem.get('dragOver')) {
      this.props.contextMenuItem.get('dragOver')(e)
    }
    this.onMouseEnter(e)
  }
  onDrop (e) {
    if (this.props.contextMenuItem.get('drop')) {
      this.props.contextMenuItem.get('drop')(e)
    }
    windowActions.setContextMenuDetail()
  }
  onContextMenu (e) {
    if (this.props.contextMenuItem.get('contextMenu')) {
      this.props.contextMenuItem.get('contextMenu')(e)
    }
    windowActions.setContextMenuDetail()
  }
  onAuxClick (e) {
    if (e.button === 1) {
      this.onClick(this.props.contextMenuItem.get('click'), true, e)
    }
  }

  onMouseEnter (e) {
    let openedSubmenuDetails = this.props.contextMenuDetail.get('openedSubmenuDetails')
    openedSubmenuDetails = openedSubmenuDetails
      ? openedSubmenuDetails.splice(this.props.submenuIndex, this.props.contextMenuDetail.get('openedSubmenuDetails').size)
      : new Immutable.List()

    if (this.hasSubmenu) {
      let node = e.target
      while (node && node.classList && !node.classList.contains('contextMenuItem')) {
        node = node.parentNode
      }
      let parentNode = node.parentNode
      while (parentNode && parentNode.classList && !parentNode.classList.contains('contextMenu')) {
        parentNode = parentNode.parentNode
      }
      const parentBoundingRect = parentNode.getBoundingClientRect()
      const boundingRect = node.getBoundingClientRect()
      openedSubmenuDetails = openedSubmenuDetails.push(Immutable.fromJS({
        y: boundingRect.top - parentBoundingRect.top - 1 + parentNode.scrollTop,
        template: this.submenu
      }))
    }
    windowActions.setContextMenuDetail(this.props.contextMenuDetail.set('openedSubmenuDetails', openedSubmenuDetails))
  }
  getLabelForItem (item) {
    const label = item.get('label')
    if (label) {
      return label
    }
    if (item.get('labelDataBind') === 'zoomLevel') {
      const activeWebview = document.querySelector('.frameWrapper.isActive webview')
      let percent = 100
      if (activeWebview) {
        percent = activeWebview.getZoomPercent()
      }
      return `${percent}%`
    }
    return ''
  }
  render () {
    const iconSize = 16
    let iconStyle = {
      minWidth: iconSize,
      width: iconSize
    }

    const icon = this.props.contextMenuItem.get('icon')
    let faIcon
    if (icon) {
      iconStyle = Object.assign(iconStyle, {
        backgroundImage: `url(${icon})`,
        backgroundSize: iconSize,
        height: iconSize
      })
    } else {
      faIcon = this.props.contextMenuItem.get('faIcon')
    }

    if (this.props.contextMenuItem.get('type') === 'separator') {
      return <div className='contextMenuItem contextMenuSeparator' role='listitem'>
        <hr />
      </div>
    }
    const props = {
      className: cx({
        contextMenuItem: true,
        hasFaIcon: faIcon,
        checkedMenuItem: this.props.contextMenuItem.get('checked'),
        hasIcon: icon || faIcon,
        selectedByKeyboard: this.props.selected,
        multiContextMenuItem: this.isMulti
      }),
      role: 'listitem'
    }

    if (typeof this.props.dataIndex === 'number') {
      props['data-index'] = this.props.dataIndex
    }

    return <div {...props}
      ref={(node) => { this.node = node }}
      draggable={this.props.contextMenuItem.get('draggable')}
      onDragStart={this.onDragStart.bind(this)}
      onDragEnd={this.onDragEnd.bind(this)}
      onDragOver={this.onDragOver.bind(this)}
      onDrop={this.onDrop.bind(this)}
      onContextMenu={this.onContextMenu.bind(this)}
      disabled={this.props.contextMenuItem.get('enabled') === false}
      onMouseEnter={this.onMouseEnter.bind(this)}
      onClick={this.onClick.bind(this, this.props.contextMenuItem.get('click'), true)}
    >
      {
        this.props.contextMenuItem.get('checked')
          ? <span className='fa fa-check contextMenuCheckIndicator' />
          : null
      }
      {
        icon || faIcon
          ? <span className={cx({
            contextMenuIcon: true,
            hasFaIcon: !!faIcon,
            fa: faIcon,
            [faIcon]: !!faIcon
          })}
            style={iconStyle}
          />
          : null
      }
      <span className='contextMenuItemText'
        data-l10n-id={this.props.contextMenuItem.get('l10nLabelId')}
      >{this.props.contextMenuItem.get('label')}</span>
      {
        this.isMulti && this.props.contextMenuItem.get('items').map((subItem) =>
          <div className='contextMenuSubItem'
            onClick={this.onClick.bind(this, subItem.get('click'), false)}
          >
            <span data-l10n-id={subItem.get('l10nLabelId')}>{this.getLabelForItem(subItem)}</span>
          </div>)
      }
      {
        this.hasSubmenu
          ? <span className='submenuIndicatorContainer'>
            <span className='submenuIndicatorSpacer' />
            <span className='submenuIndicator fa fa-chevron-right' />
          </span>
          : this.hasAccelerator
          ? <span className='submenuIndicatorContainer'>
            <span className='submenuIndicatorSpacer' />
            <span className='accelerator'>{formatAccelerator(this.accelerator)}</span>
          </span>
          : null
      }
    </div>
  }
}

module.exports = ContextMenuItem
<commit_msg>replace classList with dataset for contextMenu Fix #10443 Auditors: @luixxiul, @nejczdovc<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 Immutable = require('immutable')

// Components
const ImmutableComponent = require('../../immutableComponent')

// Actions
const windowActions = require('../../../../../js/actions/windowActions')

// Utils
const cx = require('../../../../../js/lib/classSet')
const {formatAccelerator} = require('../../../../common/lib/formatUtil')
const {elementHasDataset} = require('../../../../../js/lib/eventUtil')

class ContextMenuItem extends ImmutableComponent {
  componentDidMount () {
    if (this.node) {
      this.node.addEventListener('auxclick', this.onAuxClick.bind(this))
    }
  }
  get submenu () {
    return this.props.contextMenuItem.get('submenu')
  }
  get items () {
    return this.props.contextMenuItem.get('items')
  }
  get hasSubmenu () {
    return this.submenu && this.submenu.size > 0
  }
  get isMulti () {
    return this.items && this.items.size > 0
  }

  get accelerator () {
    const accelerator = this.props.contextMenuItem.get('accelerator')
    return accelerator && typeof accelerator === 'string'
      ? accelerator.trim()
      : null
  }
  get hasAccelerator () {
    return this.accelerator !== null
  }
  onClick (clickAction, shouldHide, e) {
    e.stopPropagation()
    if (clickAction) {
      if (shouldHide) {
        setImmediate(() => windowActions.resetMenuState())
      }
      clickAction(e)
    }
  }
  onDragStart (e) {
    if (this.props.contextMenuItem.get('dragStart')) {
      this.props.contextMenuItem.get('dragStart')(e)
    }
  }
  onDragEnd (e) {
    if (this.props.contextMenuItem.get('dragEnd')) {
      this.props.contextMenuItem.get('dragEnd')(e)
    }
  }
  onDragOver (e) {
    if (this.props.contextMenuItem.get('dragOver')) {
      this.props.contextMenuItem.get('dragOver')(e)
    }
    this.onMouseEnter(e)
  }
  onDrop (e) {
    if (this.props.contextMenuItem.get('drop')) {
      this.props.contextMenuItem.get('drop')(e)
    }
    windowActions.setContextMenuDetail()
  }
  onContextMenu (e) {
    if (this.props.contextMenuItem.get('contextMenu')) {
      this.props.contextMenuItem.get('contextMenu')(e)
    }
    windowActions.setContextMenuDetail()
  }
  onAuxClick (e) {
    if (e.button === 1) {
      this.onClick(this.props.contextMenuItem.get('click'), true, e)
    }
  }

  onMouseEnter (e) {
    let openedSubmenuDetails = this.props.contextMenuDetail.get('openedSubmenuDetails')
    openedSubmenuDetails = openedSubmenuDetails
      ? openedSubmenuDetails.splice(this.props.submenuIndex, this.props.contextMenuDetail.get('openedSubmenuDetails').size)
      : new Immutable.List()

    if (this.hasSubmenu) {
      let node = e.target
      while (node && !elementHasDataset(node, 'contextMenuItem')) {
        node = node.parentNode
      }
      let parentNode = node.parentNode
      while (parentNode && !elementHasDataset(parentNode, 'contextMenu')) {
        parentNode = parentNode.parentNode
      }
      const parentBoundingRect = parentNode.getBoundingClientRect()
      const boundingRect = node.getBoundingClientRect()
      openedSubmenuDetails = openedSubmenuDetails.push(Immutable.fromJS({
        y: boundingRect.top - parentBoundingRect.top - 1 + parentNode.scrollTop,
        template: this.submenu
      }))
    }
    windowActions.setContextMenuDetail(this.props.contextMenuDetail.set('openedSubmenuDetails', openedSubmenuDetails))
  }
  getLabelForItem (item) {
    const label = item.get('label')
    if (label) {
      return label
    }
    if (item.get('labelDataBind') === 'zoomLevel') {
      const activeWebview = document.querySelector('.frameWrapper.isActive webview')
      let percent = 100
      if (activeWebview) {
        percent = activeWebview.getZoomPercent()
      }
      return `${percent}%`
    }
    return ''
  }
  render () {
    const iconSize = 16
    let iconStyle = {
      minWidth: iconSize,
      width: iconSize
    }

    const icon = this.props.contextMenuItem.get('icon')
    let faIcon
    if (icon) {
      iconStyle = Object.assign(iconStyle, {
        backgroundImage: `url(${icon})`,
        backgroundSize: iconSize,
        height: iconSize
      })
    } else {
      faIcon = this.props.contextMenuItem.get('faIcon')
    }

    if (this.props.contextMenuItem.get('type') === 'separator') {
      return <div className='contextMenuItem contextMenuSeparator' role='listitem'>
        <hr />
      </div>
    }
    const props = {
      className: cx({
        contextMenuItem: true,
        hasFaIcon: faIcon,
        checkedMenuItem: this.props.contextMenuItem.get('checked'),
        hasIcon: icon || faIcon,
        selectedByKeyboard: this.props.selected,
        multiContextMenuItem: this.isMulti
      }),
      role: 'listitem'
    }

    if (typeof this.props.dataIndex === 'number') {
      props['data-index'] = this.props.dataIndex
    }

    return <div {...props}
      data-context-menu-item
      ref={(node) => { this.node = node }}
      draggable={this.props.contextMenuItem.get('draggable')}
      onDragStart={this.onDragStart.bind(this)}
      onDragEnd={this.onDragEnd.bind(this)}
      onDragOver={this.onDragOver.bind(this)}
      onDrop={this.onDrop.bind(this)}
      onContextMenu={this.onContextMenu.bind(this)}
      disabled={this.props.contextMenuItem.get('enabled') === false}
      onMouseEnter={this.onMouseEnter.bind(this)}
      onClick={this.onClick.bind(this, this.props.contextMenuItem.get('click'), true)}
    >
      {
        this.props.contextMenuItem.get('checked')
          ? <span className='fa fa-check contextMenuCheckIndicator' />
          : null
      }
      {
        icon || faIcon
          ? <span className={cx({
            contextMenuIcon: true,
            hasFaIcon: !!faIcon,
            fa: faIcon,
            [faIcon]: !!faIcon
          })}
            style={iconStyle}
          />
          : null
      }
      <span className='contextMenuItemText'
        data-l10n-id={this.props.contextMenuItem.get('l10nLabelId')}
      >{this.props.contextMenuItem.get('label')}</span>
      {
        this.isMulti && this.props.contextMenuItem.get('items').map((subItem) =>
          <div className='contextMenuSubItem'
            onClick={this.onClick.bind(this, subItem.get('click'), false)}
          >
            <span data-l10n-id={subItem.get('l10nLabelId')}>{this.getLabelForItem(subItem)}</span>
          </div>)
      }
      {
        this.hasSubmenu
          ? <span className='submenuIndicatorContainer'>
            <span className='submenuIndicatorSpacer' />
            <span className='submenuIndicator fa fa-chevron-right' />
          </span>
          : this.hasAccelerator
          ? <span className='submenuIndicatorContainer'>
            <span className='submenuIndicatorSpacer' />
            <span className='accelerator'>{formatAccelerator(this.accelerator)}</span>
          </span>
          : null
      }
    </div>
  }
}

module.exports = ContextMenuItem

{'fraction_non_alphanumeric': 0.14060758082497213, 'fraction_numerical': 0.003274804905239688, 'mean_word_length': 2.684034907597536, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 57, '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': '2141221', 'n_tokens_mistral': 4370, 'n_tokens_neox': 4323, 'n_words': 736}