<commit_before>import Bootable from './bootable'
import { consoleWarn } from '../util/console'

function validateAttachTarget (val) {
  const type = typeof val

  if (type === 'boolean' || type === 'string') return true

  return val.nodeType === Node.ELEMENT_NODE
}

/* @vue/component */
export default {
  name: 'detachable',

  mixins: [Bootable],

  props: {
    attach: {
      type: null,
      default: false,
      validator: validateAttachTarget
    },
    contentClass: {
      default: ''
    }
  },

  data: () => ({
    hasDetached: false
  }),

  watch: {
    attach () {
      this.hasDetached = false
      this.initDetach()
    },
    hasContent: 'initDetach'
  },

  beforeMount () {
    this.$nextTick(() => {
      if (this.activatorNode && this.activatorNode.elm) {
        this.$el.parentNode.insertBefore(this.activatorNode.elm, this.$el)
      }
    })
  },

  mounted () {
    !this.lazy && this.initDetach()
  },

  deactivated () {
    this.isActive = false
  },

  beforeDestroy () {
    if (!this.$refs.content) return

    // IE11 Fix
    try {
      this.$refs.content.parentNode.removeChild(this.$refs.content)
    } catch (e) { console.log(e) }
  },

  methods: {
    getScopeIdAttrs () {
      const scopeId = this.$vnode && this.$vnode.context.$options._scopeId
      return scopeId && {
        [scopeId]: ''
      }
    },
    initDetach () {
      if (this._isDestroyed ||
        !this.$refs.content ||
        this.hasDetached ||
        // Leave menu in place if attached
        // and dev has not changed target
        this.attach === '' || // If used as a boolean prop (<v-menu attach>)
        this.attach === true || // If bound to a boolean (<v-menu :attach="true">)
        this.attach === 'attach' // If bound as boolean prop in pug (v-menu(attach))
      ) return

      let target
      if (this.attach === false) {
        // Default, detach to app
        target = document.querySelector('[data-app]')
      } else if (typeof this.attach === 'string') {
        // CSS selector
        target = document.querySelector(this.attach)
      } else {
        // DOM Element
        target = this.attach
      }

      if (!target) {
        consoleWarn(`Unable to locate target ${this.attach || '[data-app]'}`, this)
        return
      }

      target.insertBefore(
        this.$refs.content,
        target.firstChild
      )

      this.hasDetached = true
    }
  }
}
<commit_msg>fix(detachable): extract all elements from activator scoped slot<commit_after>import Bootable from './bootable'
import { consoleWarn } from '../util/console'

function validateAttachTarget (val) {
  const type = typeof val

  if (type === 'boolean' || type === 'string') return true

  return val.nodeType === Node.ELEMENT_NODE
}

/* @vue/component */
export default {
  name: 'detachable',

  mixins: [Bootable],

  props: {
    attach: {
      type: null,
      default: false,
      validator: validateAttachTarget
    },
    contentClass: {
      default: ''
    }
  },

  data: () => ({
    hasDetached: false
  }),

  watch: {
    attach () {
      this.hasDetached = false
      this.initDetach()
    },
    hasContent: 'initDetach'
  },

  beforeMount () {
    this.$nextTick(() => {
      if (this.activatorNode) {
        const activator = Array.isArray(this.activatorNode) ? this.activatorNode : [this.activatorNode]
        activator.forEach(node => {
          node.elm && this.$el.parentNode.insertBefore(node.elm, this.$el)
        })
      }
    })
  },

  mounted () {
    !this.lazy && this.initDetach()
  },

  deactivated () {
    this.isActive = false
  },

  beforeDestroy () {
    if (!this.$refs.content) return

    // IE11 Fix
    try {
      this.$refs.content.parentNode.removeChild(this.$refs.content)
    } catch (e) { console.log(e) }
  },

  methods: {
    getScopeIdAttrs () {
      const scopeId = this.$vnode && this.$vnode.context.$options._scopeId
      return scopeId && {
        [scopeId]: ''
      }
    },
    initDetach () {
      if (this._isDestroyed ||
        !this.$refs.content ||
        this.hasDetached ||
        // Leave menu in place if attached
        // and dev has not changed target
        this.attach === '' || // If used as a boolean prop (<v-menu attach>)
        this.attach === true || // If bound to a boolean (<v-menu :attach="true">)
        this.attach === 'attach' // If bound as boolean prop in pug (v-menu(attach))
      ) return

      let target
      if (this.attach === false) {
        // Default, detach to app
        target = document.querySelector('[data-app]')
      } else if (typeof this.attach === 'string') {
        // CSS selector
        target = document.querySelector(this.attach)
      } else {
        // DOM Element
        target = this.attach
      }

      if (!target) {
        consoleWarn(`Unable to locate target ${this.attach || '[data-app]'}`, this)
        return
      }

      target.insertBefore(
        this.$refs.content,
        target.firstChild
      )

      this.hasDetached = true
    }
  }
}

{'fraction_non_alphanumeric': 0.14532117367168915, 'fraction_numerical': 0.0007930214115781126, 'mean_word_length': 2.0894060012247397, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 12, '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': '5312920', 'n_tokens_mistral': 1578, 'n_tokens_neox': 1536, 'n_words': 355}