<commit_before>define({
  root:{
    "DELETE":
      "${this.getLabel({formatLength: 'long', locale: 'nl'})}$ is verwijderd. Het venster werd gesloten.",

    "POST":
      "${this.getLabel({formatLength: 'long', locale: 'nl'})}$ is succesvol aangemaakt.",

    "PUT":
      "De nieuwe waarden voor ${this.getLabel({formatLength: 'long', locale: 'nl'})}$ zijn opgeslagen.",

    "ppwcode-vernacular-persistence/IdNotFoundException":
      "${this.getLabel({formatLength: 'long', locale: 'nl'})}$ bestaat niet meer. Het venster werd gesloten.",

    "ppwcode-vernacular-persistence/ObjectAlreadyChangedException":
      "${this.subject.getLabel({formatLength: 'long', locale: 'nl'})}$ is ondertussen reeds in een ander venster " +
      "of door een andere gebruiker aangepast. Bekijk of uw wijzigingen nog nodig zijn, en herhaal ze indien nodig.",

    "ppwcode-vernacular-exceptions/SemanticException[NOT UNIQUE]":
      "Een waarde voor ${this.subject.getLabel({formatLength: 'long', locale: 'nl'})}$ die uniek moet zijn, " +
      "is niet uniek. Pas de gegevens aan, en probeer opnieuw.",

    "ppwcode-vernacular-exceptions/SemanticException":
      "De ingevulde waarden voor ${this.subject.getLabel({formatLength: 'long', locale: 'nl'})}$ worden door de " +
      "server niet aanvaard " + "(${(this.exception.key ? this.exception.key : '') + " +
      "(this.exception.cause ? JSON.stringify(this.exception.cause) : ''}$). Pas de gegevens aan, en probeer opnieuw.",

    "ppwcode-vernacular-exceptions/SecurityException":
      "De gevraagde gegevens zijn voor u niet toegankelijk.",

    "error":
      "Er heeft zich een onverwachte situatie voorgedaan. We verontschuldigen ons, maar uw " +
      "laatste wijzigingen zijn niet opgeslagen. " +
      "Herlaad de pagina, en probeer opnieuw. Indien de fout zich " +
      "blijft herhalen, kan u ons contacteren. (${this.exception.message || this.exception.toString()}$)"
  }
});
<commit_msg>Styles messages for CrudDaoNewsFlash.<commit_after>define({
  root:{
    "DELETE":
      "
${this.getLabel({formatLength: 'long', locale: 'nl'})}$ is verwijderd.
" +
      "
Het venster werd gesloten.
",

    "POST":
      "${this.getLabel({formatLength: 'long', locale: 'nl'})}$ is succesvol " +
      "aangemaakt.",

    "PUT":
      "De nieuwe waarden voor ${this.getLabel({formatLength: 'long', locale: 'nl'})}$ " +
      "zijn opgeslagen.",

    "ppwcode-vernacular-persistence/IdNotFoundException":
      "
${this.getLabel({formatLength: 'long', locale: 'nl'})}$ bestaat niet " +
      "meer.
" +
      "
Het venster werd gesloten.
",

    "ppwcode-vernacular-persistence/ObjectAlreadyChangedException":
      "
${this.subject.getLabel({formatLength: 'long', locale: 'nl'})}$ is " +
      "ondertussen reeds in een ander venster of door een andere gebruiker aangepast.
" +
      "
Bekijk of uw wijzigingen nog nodig zijn, en herhaal ze indien nodig.
",

    "ppwcode-vernacular-exceptions/SemanticException[NOT UNIQUE]":
      "
Een waarde voor " +
      "${this.subject.getLabel({formatLength: 'long', locale: 'nl'})}$ die uniek moet " +
      "zijn, is niet uniek.
" +
      "
Pas de gegevens aan, en probeer opnieuw.
",

    "ppwcode-vernacular-exceptions/SemanticException":
      "
De ingevulde waarden voor " +
      "${this.subject.getLabel({formatLength: 'long', locale: 'nl'})}$ worden door " +
      "de server niet aanvaard.
" +
      "
(${(this.exception.key ? this.exception.key : '') + (this.exception.cause ? JSON.stringify(this.exception.cause) : '')}$)
" +
      "
Pas de gegevens aan, en probeer opnieuw.
",

    "ppwcode-vernacular-exceptions/SecurityException":
      "De gevraagde gegevens zijn voor u niet toegankelijk.",

    "error":
      "
Er heeft zich een onverwachte situatie voorgedaan. We verontschuldigen ons, maar uw laatste wijzigingen " +
      "zijn niet opgeslagen.
" +
      "
Herlaad de pagina, en probeer opnieuw.
" +
      "
Indien de fout zich blijft herhalen, kan u ons contacteren.
" +
      "
(${this.exception.message || this.exception.toString()}$)
"
  }
});
<|endoftext|>


<commit_before>import { h, ref, watch, computed, getCurrentInstance } from 'vue'

import QBtn from '../btn/QBtn.js'
import QInput from '../input/QInput.js'

import useDark, { useDarkProps } from '../../composables/private/use-dark.js'

import { createComponent } from '../../utils/private/create.js'
import { between } from '../../utils/format.js'
import { isKeyCode } from '../../utils/private/key-composition.js'

export default createComponent({
  name: 'QPagination',

  props: {
    ...useDarkProps,

    modelValue: {
      type: Number,
      required: true
    },
    min: {
      type: Number,
      default: 1
    },
    max: {
      type: Number,
      required: true
    },

    color: {
      type: String,
      default: 'primary'
    },
    textColor: String,

    activeColor: String,
    activeTextColor: String,

    inputStyle: [ Array, String, Object ],
    inputClass: [ Array, String, Object ],

    size: String,

    disable: Boolean,

    input: Boolean,

    iconPrev: String,
    iconNext: String,
    iconFirst: String,
    iconLast: String,

    toFn: Function,

    boundaryLinks: {
      type: Boolean,
      default: null
    },
    boundaryNumbers: {
      type: Boolean,
      default: null
    },
    directionLinks: {
      type: Boolean,
      default: null
    },
    ellipses: {
      type: Boolean,
      default: null
    },
    maxPages: {
      type: Number,
      default: 0,
      validator: v => v >= 0
    },

    ripple: {
      type: [ Boolean, Object ],
      default: null
    },

    round: Boolean,
    rounded: Boolean,

    flat: Boolean,
    outline: Boolean,
    unelevated: Boolean,
    push: Boolean,
    glossy: Boolean,

    dense: Boolean,
    padding: {
      type: String,
      default: '3px 2px'
    }
  },

  emits: [ 'update:modelValue' ],

  setup (props, { emit }) {
    const { proxy } = getCurrentInstance()
    const { $q } = proxy

    const isDark = useDark(props, $q)

    const newPage = ref(null)
    const model = computed({
      get: () => props.modelValue,
      set: val => {
        val = parseInt(val, 10)
        if (props.disable || isNaN(val)) {
          return
        }
        const value = between(val, props.min, props.max)
        if (props.modelValue !== value) {
          emit('update:modelValue', value)
        }
      }
    })

    watch(() => props.min + props.max, () => {
      model.value = props.modelValue
    })

    function getBool (val, otherwise) {
      return [ true, false ].includes(val)
        ? val
        : otherwise
    }

    const classes = computed(() =>
      'q-pagination row no-wrap items-center'
      + (props.disable === true ? ' disabled' : '')
    )
    const inputPlaceholder = computed(() => model.value + ' / ' + props.max)
    const __boundaryLinks = computed(() => getBool(props.boundaryLinks, props.input))
    const __boundaryNumbers = computed(() => getBool(props.boundaryNumbers, !props.input))
    const __directionLinks = computed(() => getBool(props.directionLinks, props.input))
    const __ellipses = computed(() => getBool(props.ellipses, !props.input))
    const icons = computed(() => {
      const ico = [
        props.iconFirst || $q.iconSet.pagination.first,
        props.iconPrev || $q.iconSet.pagination.prev,
        props.iconNext || $q.iconSet.pagination.next,
        props.iconLast || $q.iconSet.pagination.last
      ]
      return $q.lang.rtl === true ? ico.reverse() : ico
    })

    const attrs = computed(() => (
      props.disable === true
        ? { 'aria-disabled': 'true' }
        : {}
    ))

    const btnProps = computed(() => ({
      round: props.round,
      rounded: props.rounded,

      outline: props.outline,
      unelevated: props.unelevated,
      push: props.push,
      glossy: props.glossy,

      dense: props.dense,
      padding: props.padding,

      color: props.color,
      flat: true,
      size: props.size,
      ripple: props.ripple !== null
        ? props.ripple
        : true
    }))

    const activeBtnProps = computed(() => ({
      flat: props.flat,
      color: props.activeColor || props.color,
      textColor: props.activeTextColor || props.textColor
    }))

    function set (value) {
      model.value = value
    }

    function setByOffset (offset) {
      model.value = model.value + offset
    }

    function updateModel () {
      model.value = newPage.value
      newPage.value = null
    }

    function getBtn (cfg, page) {
      const data = { ...btnProps.value, ...cfg }

      if (page !== void 0) {
        if (props.toFn !== void 0) {
          data.to = props.toFn(page)
        }
        else {
          data.onClick = () => set(page)
        }
      }

      return h(QBtn, data)
    }

    // expose public methods
    Object.assign(proxy, { set, setByOffset })

    return () => {
      const
        contentStart = [],
        contentEnd = [],
        contentMiddle = []

      if (__boundaryLinks.value) {
        contentStart.push(getBtn({
          key: 'bls',
          disable: props.disable || props.modelValue <= props.min,
          icon: icons.value[ 0 ]
        }, props.min))
        contentEnd.unshift(getBtn({
          key: 'ble',
          disable: props.disable || props.modelValue >= props.max,
          icon: icons.value[ 3 ]
        }, props.max))
      }

      if (__directionLinks.value) {
        contentStart.push(getBtn({
          key: 'bdp',
          disable: props.disable || props.modelValue <= props.min,
          icon: icons.value[ 1 ]
        }, props.modelValue - 1))
        contentEnd.unshift(getBtn({
          key: 'bdn',
          disable: props.disable || props.modelValue >= props.max,
          icon: icons.value[ 2 ]
        }, props.modelValue + 1))
      }

      if (props.input === true) {
        contentMiddle.push(h(QInput, {
          class: 'inline',
          style: {
            width: `${ inputPlaceholder.value.length / 1.5 }em`
          },
          type: 'number',
          dense: true,
          value: newPage.value,
          disable: props.disable,
          dark: isDark.value,
          borderless: true,
          inputClass: props.inputClass,
          inputStyle: props.inputStyle,
          placeholder: inputPlaceholder.value,
          min: props.min,
          max: props.max,
          'onUpdate:modelValue' (value) { newPage.value = value },
          onKeyup (e) { isKeyCode(e, 13) === true && updateModel() },
          onBlur: updateModel
        }))
      }
      else { // is type select
        let
          maxPages = Math.max(
            props.maxPages,
            1 + (__ellipses.value ? 2 : 0) + (__boundaryNumbers.value ? 2 : 0)
          ),
          pgFrom = props.min,
          pgTo = props.max,
          ellipsesStart = false,
          ellipsesEnd = false,
          boundaryStart = false,
          boundaryEnd = false

        if (props.maxPages && maxPages < (props.max - props.min + 1)) {
          maxPages = 1 + Math.floor(maxPages / 2) * 2
          pgFrom = Math.max(props.min, Math.min(props.max - maxPages + 1, props.modelValue - Math.floor(maxPages / 2)))
          pgTo = Math.min(props.max, pgFrom + maxPages - 1)
          if (__boundaryNumbers.value) {
            boundaryStart = true
            pgFrom += 1
          }
          if (__ellipses.value && pgFrom > (props.min + (__boundaryNumbers.value ? 1 : 0))) {
            ellipsesStart = true
            pgFrom += 1
          }
          if (__boundaryNumbers.value) {
            boundaryEnd = true
            pgTo -= 1
          }
          if (__ellipses.value && pgTo < (props.max - (__boundaryNumbers.value ? 1 : 0))) {
            ellipsesEnd = true
            pgTo -= 1
          }
        }
        const style = {
          minWidth: `${ Math.max(2, String(props.max).length) }em`
        }
        if (boundaryStart) {
          const active = props.min === props.modelValue
          contentStart.push(getBtn({
            key: 'bns',
            style,
            disable: props.disable,
            flat: !active,
            textColor: active ? props.textColor : void 0,
            label: props.min
          }, props.min))
        }
        if (boundaryEnd) {
          const active = props.max === props.modelValue
          contentEnd.unshift(getBtn({
            key: 'bne',
            style,
            disable: props.disable,
            flat: !active,
            textColor: active ? props.textColor : void 0,
            label: props.max
          }, props.max))
        }
        if (ellipsesStart) {
          contentStart.push(getBtn({
            key: 'bes',
            style,
            disable: props.disable,
            label: '…',
            ripple: false
          }, pgFrom - 1))
        }
        if (ellipsesEnd) {
          contentEnd.unshift(getBtn({
            key: 'bee',
            style,
            disable: props.disable,
            label: '…',
            ripple: false
          }, pgTo + 1))
        }
        for (let i = pgFrom; i <= pgTo; i++) {
          const btn = {
            key: `bpg${ i }`,
            style,
            disable: props.disable,
            label: i
          }
          if (i === props.modelValue) {
            Object.assign(btn, activeBtnProps.value)
          }
          contentMiddle.push(getBtn(btn, i))
        }
      }

      return h('div', {
        class: classes.value,
        ...attrs.value
      }, [
        contentStart,

        h('div', {
          class: 'row justify-center'
        }, [
          contentMiddle
        ]),

        contentEnd
      ])
    }
  }
})
<commit_msg>fix(QPagination): activeColor on boundary links (#11442)<commit_after>import { h, ref, watch, computed, getCurrentInstance } from 'vue'

import QBtn from '../btn/QBtn.js'
import QInput from '../input/QInput.js'

import useDark, { useDarkProps } from '../../composables/private/use-dark.js'

import { createComponent } from '../../utils/private/create.js'
import { between } from '../../utils/format.js'
import { isKeyCode } from '../../utils/private/key-composition.js'

export default createComponent({
  name: 'QPagination',

  props: {
    ...useDarkProps,

    modelValue: {
      type: Number,
      required: true
    },
    min: {
      type: Number,
      default: 1
    },
    max: {
      type: Number,
      required: true
    },

    color: {
      type: String,
      default: 'primary'
    },
    textColor: String,

    activeColor: String,
    activeTextColor: String,

    inputStyle: [ Array, String, Object ],
    inputClass: [ Array, String, Object ],

    size: String,

    disable: Boolean,

    input: Boolean,

    iconPrev: String,
    iconNext: String,
    iconFirst: String,
    iconLast: String,

    toFn: Function,

    boundaryLinks: {
      type: Boolean,
      default: null
    },
    boundaryNumbers: {
      type: Boolean,
      default: null
    },
    directionLinks: {
      type: Boolean,
      default: null
    },
    ellipses: {
      type: Boolean,
      default: null
    },
    maxPages: {
      type: Number,
      default: 0,
      validator: v => v >= 0
    },

    ripple: {
      type: [ Boolean, Object ],
      default: null
    },

    round: Boolean,
    rounded: Boolean,

    flat: Boolean,
    outline: Boolean,
    unelevated: Boolean,
    push: Boolean,
    glossy: Boolean,

    dense: Boolean,
    padding: {
      type: String,
      default: '3px 2px'
    }
  },

  emits: [ 'update:modelValue' ],

  setup (props, { emit }) {
    const { proxy } = getCurrentInstance()
    const { $q } = proxy

    const isDark = useDark(props, $q)

    const newPage = ref(null)
    const model = computed({
      get: () => props.modelValue,
      set: val => {
        val = parseInt(val, 10)
        if (props.disable || isNaN(val)) {
          return
        }
        const value = between(val, props.min, props.max)
        if (props.modelValue !== value) {
          emit('update:modelValue', value)
        }
      }
    })

    watch(() => props.min + props.max, () => {
      model.value = props.modelValue
    })

    function getBool (val, otherwise) {
      return [ true, false ].includes(val)
        ? val
        : otherwise
    }

    const classes = computed(() =>
      'q-pagination row no-wrap items-center'
      + (props.disable === true ? ' disabled' : '')
    )
    const inputPlaceholder = computed(() => model.value + ' / ' + props.max)
    const __boundaryLinks = computed(() => getBool(props.boundaryLinks, props.input))
    const __boundaryNumbers = computed(() => getBool(props.boundaryNumbers, !props.input))
    const __directionLinks = computed(() => getBool(props.directionLinks, props.input))
    const __ellipses = computed(() => getBool(props.ellipses, !props.input))
    const icons = computed(() => {
      const ico = [
        props.iconFirst || $q.iconSet.pagination.first,
        props.iconPrev || $q.iconSet.pagination.prev,
        props.iconNext || $q.iconSet.pagination.next,
        props.iconLast || $q.iconSet.pagination.last
      ]
      return $q.lang.rtl === true ? ico.reverse() : ico
    })

    const attrs = computed(() => (
      props.disable === true
        ? { 'aria-disabled': 'true' }
        : {}
    ))

    const btnProps = computed(() => ({
      round: props.round,
      rounded: props.rounded,

      outline: props.outline,
      unelevated: props.unelevated,
      push: props.push,
      glossy: props.glossy,

      dense: props.dense,
      padding: props.padding,

      color: props.color,
      flat: true,
      size: props.size,
      ripple: props.ripple !== null
        ? props.ripple
        : true
    }))

    const activeBtnProps = computed(() => ({
      flat: props.flat,
      color: props.activeColor || props.color,
      textColor: props.activeTextColor || props.textColor
    }))

    function set (value) {
      model.value = value
    }

    function setByOffset (offset) {
      model.value = model.value + offset
    }

    function updateModel () {
      model.value = newPage.value
      newPage.value = null
    }

    function getBtn (cfg, page) {
      const data = { ...btnProps.value, ...cfg }

      if (page !== void 0) {
        if (props.toFn !== void 0) {
          data.to = props.toFn(page)
        }
        else {
          data.onClick = () => set(page)
        }
      }

      return h(QBtn, data)
    }

    // expose public methods
    Object.assign(proxy, { set, setByOffset })

    return () => {
      const
        contentStart = [],
        contentEnd = [],
        contentMiddle = []

      if (__boundaryLinks.value) {
        contentStart.push(getBtn({
          key: 'bls',
          disable: props.disable || props.modelValue <= props.min,
          icon: icons.value[ 0 ]
        }, props.min))
        contentEnd.unshift(getBtn({
          key: 'ble',
          disable: props.disable || props.modelValue >= props.max,
          icon: icons.value[ 3 ]
        }, props.max))
      }

      if (__directionLinks.value) {
        contentStart.push(getBtn({
          key: 'bdp',
          disable: props.disable || props.modelValue <= props.min,
          icon: icons.value[ 1 ]
        }, props.modelValue - 1))
        contentEnd.unshift(getBtn({
          key: 'bdn',
          disable: props.disable || props.modelValue >= props.max,
          icon: icons.value[ 2 ]
        }, props.modelValue + 1))
      }

      if (props.input === true) {
        contentMiddle.push(h(QInput, {
          class: 'inline',
          style: {
            width: `${ inputPlaceholder.value.length / 1.5 }em`
          },
          type: 'number',
          dense: true,
          value: newPage.value,
          disable: props.disable,
          dark: isDark.value,
          borderless: true,
          inputClass: props.inputClass,
          inputStyle: props.inputStyle,
          placeholder: inputPlaceholder.value,
          min: props.min,
          max: props.max,
          'onUpdate:modelValue' (value) { newPage.value = value },
          onKeyup (e) { isKeyCode(e, 13) === true && updateModel() },
          onBlur: updateModel
        }))
      }
      else { // is type select
        let
          maxPages = Math.max(
            props.maxPages,
            1 + (__ellipses.value ? 2 : 0) + (__boundaryNumbers.value ? 2 : 0)
          ),
          pgFrom = props.min,
          pgTo = props.max,
          ellipsesStart = false,
          ellipsesEnd = false,
          boundaryStart = false,
          boundaryEnd = false

        if (props.maxPages && maxPages < (props.max - props.min + 1)) {
          maxPages = 1 + Math.floor(maxPages / 2) * 2
          pgFrom = Math.max(props.min, Math.min(props.max - maxPages + 1, props.modelValue - Math.floor(maxPages / 2)))
          pgTo = Math.min(props.max, pgFrom + maxPages - 1)
          if (__boundaryNumbers.value) {
            boundaryStart = true
            pgFrom += 1
          }
          if (__ellipses.value && pgFrom > (props.min + (__boundaryNumbers.value ? 1 : 0))) {
            ellipsesStart = true
            pgFrom += 1
          }
          if (__boundaryNumbers.value) {
            boundaryEnd = true
            pgTo -= 1
          }
          if (__ellipses.value && pgTo < (props.max - (__boundaryNumbers.value ? 1 : 0))) {
            ellipsesEnd = true
            pgTo -= 1
          }
        }
        const style = {
          minWidth: `${ Math.max(2, String(props.max).length) }em`
        }
        if (boundaryStart) {
          const active = props.min === props.modelValue
          contentStart.push(getBtn({
            key: 'bns',
            style,
            disable: props.disable,
            flat: !active,
            label: props.min,
            ...(active ? activeBtnProps.value : {})
          }, props.min))
        }
        if (boundaryEnd) {
          const active = props.max === props.modelValue
          contentEnd.unshift(getBtn({
            key: 'bne',
            style,
            disable: props.disable,
            flat: !active,
            label: props.max,
            ...(active ? activeBtnProps.value : {})
          }, props.max))
        }
        if (ellipsesStart) {
          contentStart.push(getBtn({
            key: 'bes',
            style,
            disable: props.disable,
            label: '…',
            ripple: false
          }, pgFrom - 1))
        }
        if (ellipsesEnd) {
          contentEnd.unshift(getBtn({
            key: 'bee',
            style,
            disable: props.disable,
            label: '…',
            ripple: false
          }, pgTo + 1))
        }
        for (let i = pgFrom; i <= pgTo; i++) {
          const btn = {
            key: `bpg${ i }`,
            style,
            disable: props.disable,
            label: i
          }
          if (i === props.modelValue) {
            Object.assign(btn, activeBtnProps.value)
          }
          contentMiddle.push(getBtn(btn, i))
        }
      }

      return h('div', {
        class: classes.value,
        ...attrs.value
      }, [
        contentStart,

        h('div', {
          class: 'row justify-center'
        }, [
          contentMiddle
        ]),

        contentEnd
      ])
    }
  }
})
<|endoftext|>


<commit_before>import Vue from 'vue'

import QBtn from '../btn/QBtn.js'
import QIcon from '../icon/QIcon.js'
import QSpinner from '../spinner/QSpinner.js'
import QCircularProgress from '../circular-progress/QCircularProgress.js'

import FileMixin from '../../mixins/file.js'
import DarkMixin from '../../mixins/dark.js'

import { stop } from '../../utils/event.js'
import { humanStorageSize } from '../../utils/format.js'
import cache from '../../utils/cache.js'

export default Vue.extend({
  name: 'QUploaderBase',

  mixins: [ DarkMixin, FileMixin ],

  props: {
    label: String,

    color: String,
    textColor: String,

    square: Boolean,
    flat: Boolean,
    bordered: Boolean,

    noThumbnails: Boolean,
    autoUpload: Boolean,
    hideUploadBtn: Boolean,

    disable: Boolean,
    readonly: Boolean
  },

  provide () {
    return {
      __qUploaderGetInput: this.__getInputControl
    }
  },

  data () {
    return {
      files: [],
      queuedFiles: [],
      uploadedFiles: [],
      dnd: false,
      expanded: false,

      uploadSize: 0,
      uploadedSize: 0
    }
  },

  watch: {
    isUploading (newVal, oldVal) {
      if (oldVal === false && newVal === true) {
        this.$emit('start')
      }
      else if (oldVal === true && newVal === false) {
        this.$emit('finish')
      }
    }
  },

  computed: {
    /*
     * When extending:
     *   Required : isUploading
     *   Optional: isBusy
     */

    canUpload () {
      return this.editable === true &&
        this.isBusy !== true &&
        this.isUploading !== true &&
        this.queuedFiles.length > 0
    },

    canAddFiles () {
      return (
        this.editable === true &&
        this.isUploading !== true &&
        // if single selection and no files are queued:
        (this.multiple === true || this.queuedFiles.length === 0) &&
        // if max-files is set and current number of files does not exceeds it:
        (this.maxFiles === void 0 || this.files.length < this.maxFilesNumber) &&
        // if max-total-size is set and current upload size does not exceeds it:
        (this.maxTotalSize === void 0 || this.uploadSize < this.maxTotalSizeNumber)
      )
    },

    uploadProgress () {
      return this.uploadSize === 0
        ? 0
        : this.uploadedSize / this.uploadSize
    },

    uploadProgressLabel () {
      return this.__getProgressLabel(this.uploadProgress)
    },

    uploadedSizeLabel () {
      return humanStorageSize(this.uploadedSize)
    },

    uploadSizeLabel () {
      return humanStorageSize(this.uploadSize)
    },

    colorClass () {
      const cls = []
      this.color !== void 0 && cls.push(`bg-${this.color}`)
      this.textColor !== void 0 && cls.push(`text-${this.textColor}`)
      return cls.join(' ')
    },

    editable () {
      return this.disable !== true && this.readonly !== true
    }
  },

  methods: {
    reset () {
      if (!this.disable) {
        this.abort()
        this.uploadedSize = 0
        this.uploadSize = 0
        this.__revokeImgURLs()
        this.files = []
        this.queuedFiles = []
        this.uploadedFiles = []
      }
    },

    removeUploadedFiles () {
      if (!this.disable) {
        this.files = this.files.filter(f => {
          if (f.__status !== 'uploaded') {
            return true
          }

          f._img !== void 0 && window.URL.revokeObjectURL(f._img.src)

          return false
        })
        this.uploadedFiles = []
      }
    },

    removeQueuedFiles () {
      if (!this.disable) {
        const removedFiles = []

        const files = this.files.filter(f => {
          if (f.__status !== 'idle' && f.__status !== 'failed') {
            return true
          }

          this.uploadSize -= f.size
          removedFiles.push(f)

          f._img !== void 0 && window.URL.revokeObjectURL(f._img.src)

          return false
        })

        if (removedFiles.length > 0) {
          this.files = files
          this.queuedFiles = []
          this.$emit('removed', removedFiles)
        }
      }
    },

    removeFile (file) {
      if (this.disable) { return }

      if (file.__status === 'uploaded') {
        this.uploadedFiles = this.uploadedFiles.filter(f => f.name !== file.name)
      }
      else if (file.__status === 'uploading') {
        file.__abort()
      }
      else {
        this.uploadSize -= file.size
      }

      this.files = this.files.filter(f => {
        if (f.name !== file.name) {
          return true
        }

        f._img !== void 0 && window.URL.revokeObjectURL(f._img.src)

        return false
      })
      this.queuedFiles = this.queuedFiles.filter(f => f.name !== file.name)
      this.$emit('removed', [ file ])
    },

    __revokeImgURLs () {
      this.files.forEach(f => {
        f._img !== void 0 && window.URL.revokeObjectURL(f._img.src)
      })
    },

    __getFileInput () {
      return this.$refs.input ||
        this.$el.getElementsByClassName('q-uploader__input')[0]
    },

    __getProgressLabel (p) {
      return (p * 100).toFixed(2) + '%'
    },

    __updateFile (file, status, uploadedSize) {
      file.__status = status

      if (status === 'idle') {
        file.__uploaded = 0
        file.__progress = 0
        file.__sizeLabel = humanStorageSize(file.size)
        file.__progressLabel = '0.00%'
        return
      }
      if (status === 'failed') {
        this.$forceUpdate()
        return
      }

      file.__uploaded = status === 'uploaded'
        ? file.size
        : uploadedSize

      file.__progress = status === 'uploaded'
        ? 1
        : Math.min(0.9999, file.__uploaded / file.size)

      file.__progressLabel = this.__getProgressLabel(file.__progress)
      this.$forceUpdate()
    },

    __addFiles (e, fileList) {
      const processedFiles = this.__processFiles(e, fileList, this.files, true)

      if (processedFiles === void 0) { return }

      const files = processedFiles
        .filter(file => this.files.findIndex(f => file.name === f.name) === -1)

      this.__getFileInput().value = ''

      if (files === void 0) { return }

      files.forEach(file => {
        this.__updateFile(file, 'idle')
        this.uploadSize += file.size

        if (this.noThumbnails !== true && file.type.toUpperCase().startsWith('IMAGE')) {
          const img = new Image()
          img.src = window.URL.createObjectURL(file)
          file.__img = img
        }
      })

      this.files = this.files.concat(files)
      this.queuedFiles = this.queuedFiles.concat(files)
      this.$emit('added', files)
      this.autoUpload === true && this.upload()
    },

    __getBtn (h, show, icon, fn) {
      if (show === true) {
        return h(QBtn, {
          props: {
            type: 'a',
            icon: this.$q.iconSet.uploader[icon],
            flat: true,
            dense: true
          },
          on: icon === 'add' ? null : { click: fn }
        }, icon === 'add' ? this.__getInputControl(h) : null)
      }
    },

    __getInputControl (h) {
      return [
        h('input', {
          ref: 'input',
          staticClass: 'q-uploader__input overflow-hidden absolute-full',
          attrs: {
            tabindex: -1,
            type: 'file',
            title: '', // try to remove default tooltip
            accept: this.accept,
            ...(this.multiple === true ? { multiple: true } : {})
          },
          on: cache(this, 'input', {
            mousedown: stop, // need to stop refocus from QBtn
            change: this.__addFiles
          })
        })
      ]
    },

    __getHeader (h) {
      if (this.$scopedSlots.header !== void 0) {
        return this.$scopedSlots.header(this)
      }

      return [
        h('div', {
          staticClass: 'q-uploader__header-content flex flex-center no-wrap q-gutter-xs'
        }, [
          this.__getBtn(h, this.queuedFiles.length > 0, 'removeQueue', this.removeQueuedFiles),
          this.__getBtn(h, this.uploadedFiles.length > 0, 'removeUploaded', this.removeUploadedFiles),

          this.isUploading === true
            ? h(QSpinner, { staticClass: 'q-uploader__spinner' })
            : null,

          h('div', { staticClass: 'col column justify-center' }, [
            this.label !== void 0
              ? h('div', { staticClass: 'q-uploader__title' }, [ this.label ])
              : null,

            h('div', { staticClass: 'q-uploader__subtitle' }, [
              this.uploadSizeLabel + ' / ' + this.uploadProgressLabel
            ])
          ]),

          this.__getBtn(h, this.canAddFiles, 'add', this.pickFiles),
          this.__getBtn(h, this.hideUploadBtn === false && this.canUpload === true, 'upload', this.upload),
          this.__getBtn(h, this.isUploading, 'clear', this.abort)
        ])
      ]
    },

    __getList (h) {
      if (this.$scopedSlots.list !== void 0) {
        return this.$scopedSlots.list(this)
      }

      return this.files.map(file => h('div', {
        key: file.name,
        staticClass: 'q-uploader__file relative-position',
        class: {
          'q-uploader__file--img': this.noThumbnails !== true && file.__img !== void 0,
          'q-uploader__file--failed': file.__status === 'failed',
          'q-uploader__file--uploaded': file.__status === 'uploaded'
        },
        style: this.noThumbnails !== true && file.__img !== void 0 ? {
          backgroundImage: 'url("' + file.__img.src + '")'
        } : null
      }, [
        h('div', {
          staticClass: 'q-uploader__file-header row flex-center no-wrap'
        }, [
          file.__status === 'failed'
            ? h(QIcon, {
              staticClass: 'q-uploader__file-status',
              props: {
                name: this.$q.iconSet.type.negative,
                color: 'negative'
              }
            })
            : null,

          h('div', { staticClass: 'q-uploader__file-header-content col' }, [
            h('div', { staticClass: 'q-uploader__title' }, [ file.name ]),
            h('div', {
              staticClass: 'q-uploader__subtitle row items-center no-wrap'
            }, [
              file.__sizeLabel + ' / ' + file.__progressLabel
            ])
          ]),

          file.__status === 'uploading'
            ? h(QCircularProgress, {
              props: {
                value: file.__progress,
                min: 0,
                max: 1,
                indeterminate: file.__progress === 0
              }
            })
            : h(QBtn, {
              props: {
                round: true,
                dense: true,
                flat: true,
                icon: this.$q.iconSet.uploader[file.__status === 'uploaded' ? 'done' : 'clear']
              },
              on: {
                click: () => { this.removeFile(file) }
              }
            })
        ])
      ]))
    }
  },

  beforeDestroy () {
    this.isUploading === true && this.abort()
    this.files.length > 0 && this.__revokeImgURLs()
  },

  render (h) {
    const children = [
      h('div', {
        staticClass: 'q-uploader__header',
        class: this.colorClass
      }, this.__getHeader(h)),

      h('div', {
        staticClass: 'q-uploader__list scroll'
      }, this.__getList(h)),

      this.__getDnd(h, 'uploader')
    ]

    this.isBusy === true && children.push(
      h('div', {
        staticClass: 'q-uploader__overlay absolute-full flex flex-center'
      }, [ h(QSpinner) ])
    )

    return h('div', {
      staticClass: 'q-uploader column no-wrap',
      class: {
        'q-uploader--dark q-dark': this.isDark,
        'q-uploader--bordered': this.bordered,
        'q-uploader--square no-border-radius': this.square,
        'q-uploader--flat no-shadow': this.flat,
        'disabled q-uploader--disable': this.disable
      },
      on: this.canAddFiles === true
        ? cache(this, 'drag', { dragover: this.__onDragOver })
        : null
    }, children)
  }
})
<commit_msg>[Feature] QUploaderBase.js adding the capture param (#7249)<commit_after>import Vue from 'vue'

import QBtn from '../btn/QBtn.js'
import QIcon from '../icon/QIcon.js'
import QSpinner from '../spinner/QSpinner.js'
import QCircularProgress from '../circular-progress/QCircularProgress.js'

import FileMixin from '../../mixins/file.js'
import DarkMixin from '../../mixins/dark.js'

import { stop } from '../../utils/event.js'
import { humanStorageSize } from '../../utils/format.js'
import cache from '../../utils/cache.js'

export default Vue.extend({
  name: 'QUploaderBase',

  mixins: [ DarkMixin, FileMixin ],

  props: {
    label: String,

    color: String,
    textColor: String,

    square: Boolean,
    flat: Boolean,
    bordered: Boolean,

    noThumbnails: Boolean,
    autoUpload: Boolean,
    hideUploadBtn: Boolean,

    disable: Boolean,
    readonly: Boolean,
    capture: String,
  },

  provide () {
    return {
      __qUploaderGetInput: this.__getInputControl
    }
  },

  data () {
    return {
      files: [],
      queuedFiles: [],
      uploadedFiles: [],
      dnd: false,
      expanded: false,

      uploadSize: 0,
      uploadedSize: 0
    }
  },

  watch: {
    isUploading (newVal, oldVal) {
      if (oldVal === false && newVal === true) {
        this.$emit('start')
      }
      else if (oldVal === true && newVal === false) {
        this.$emit('finish')
      }
    }
  },

  computed: {
    /*
     * When extending:
     *   Required : isUploading
     *   Optional: isBusy
     */

    canUpload () {
      return this.editable === true &&
        this.isBusy !== true &&
        this.isUploading !== true &&
        this.queuedFiles.length > 0
    },

    canAddFiles () {
      return (
        this.editable === true &&
        this.isUploading !== true &&
        // if single selection and no files are queued:
        (this.multiple === true || this.queuedFiles.length === 0) &&
        // if max-files is set and current number of files does not exceeds it:
        (this.maxFiles === void 0 || this.files.length < this.maxFilesNumber) &&
        // if max-total-size is set and current upload size does not exceeds it:
        (this.maxTotalSize === void 0 || this.uploadSize < this.maxTotalSizeNumber)
      )
    },

    uploadProgress () {
      return this.uploadSize === 0
        ? 0
        : this.uploadedSize / this.uploadSize
    },

    uploadProgressLabel () {
      return this.__getProgressLabel(this.uploadProgress)
    },

    uploadedSizeLabel () {
      return humanStorageSize(this.uploadedSize)
    },

    uploadSizeLabel () {
      return humanStorageSize(this.uploadSize)
    },

    colorClass () {
      const cls = []
      this.color !== void 0 && cls.push(`bg-${this.color}`)
      this.textColor !== void 0 && cls.push(`text-${this.textColor}`)
      return cls.join(' ')
    },

    editable () {
      return this.disable !== true && this.readonly !== true
    }
  },

  methods: {
    reset () {
      if (!this.disable) {
        this.abort()
        this.uploadedSize = 0
        this.uploadSize = 0
        this.__revokeImgURLs()
        this.files = []
        this.queuedFiles = []
        this.uploadedFiles = []
      }
    },

    removeUploadedFiles () {
      if (!this.disable) {
        this.files = this.files.filter(f => {
          if (f.__status !== 'uploaded') {
            return true
          }

          f._img !== void 0 && window.URL.revokeObjectURL(f._img.src)

          return false
        })
        this.uploadedFiles = []
      }
    },

    removeQueuedFiles () {
      if (!this.disable) {
        const removedFiles = []

        const files = this.files.filter(f => {
          if (f.__status !== 'idle' && f.__status !== 'failed') {
            return true
          }

          this.uploadSize -= f.size
          removedFiles.push(f)

          f._img !== void 0 && window.URL.revokeObjectURL(f._img.src)

          return false
        })

        if (removedFiles.length > 0) {
          this.files = files
          this.queuedFiles = []
          this.$emit('removed', removedFiles)
        }
      }
    },

    removeFile (file) {
      if (this.disable) { return }

      if (file.__status === 'uploaded') {
        this.uploadedFiles = this.uploadedFiles.filter(f => f.name !== file.name)
      }
      else if (file.__status === 'uploading') {
        file.__abort()
      }
      else {
        this.uploadSize -= file.size
      }

      this.files = this.files.filter(f => {
        if (f.name !== file.name) {
          return true
        }

        f._img !== void 0 && window.URL.revokeObjectURL(f._img.src)

        return false
      })
      this.queuedFiles = this.queuedFiles.filter(f => f.name !== file.name)
      this.$emit('removed', [ file ])
    },

    __revokeImgURLs () {
      this.files.forEach(f => {
        f._img !== void 0 && window.URL.revokeObjectURL(f._img.src)
      })
    },

    __getFileInput () {
      return this.$refs.input ||
        this.$el.getElementsByClassName('q-uploader__input')[0]
    },

    __getProgressLabel (p) {
      return (p * 100).toFixed(2) + '%'
    },

    __updateFile (file, status, uploadedSize) {
      file.__status = status

      if (status === 'idle') {
        file.__uploaded = 0
        file.__progress = 0
        file.__sizeLabel = humanStorageSize(file.size)
        file.__progressLabel = '0.00%'
        return
      }
      if (status === 'failed') {
        this.$forceUpdate()
        return
      }

      file.__uploaded = status === 'uploaded'
        ? file.size
        : uploadedSize

      file.__progress = status === 'uploaded'
        ? 1
        : Math.min(0.9999, file.__uploaded / file.size)

      file.__progressLabel = this.__getProgressLabel(file.__progress)
      this.$forceUpdate()
    },

    __addFiles (e, fileList) {
      const processedFiles = this.__processFiles(e, fileList, this.files, true)

      if (processedFiles === void 0) { return }

      const files = processedFiles
        .filter(file => this.files.findIndex(f => file.name === f.name) === -1)

      this.__getFileInput().value = ''

      if (files === void 0) { return }

      files.forEach(file => {
        this.__updateFile(file, 'idle')
        this.uploadSize += file.size

        if (this.noThumbnails !== true && file.type.toUpperCase().startsWith('IMAGE')) {
          const img = new Image()
          img.src = window.URL.createObjectURL(file)
          file.__img = img
        }
      })

      this.files = this.files.concat(files)
      this.queuedFiles = this.queuedFiles.concat(files)
      this.$emit('added', files)
      this.autoUpload === true && this.upload()
    },

    __getBtn (h, show, icon, fn) {
      if (show === true) {
        return h(QBtn, {
          props: {
            type: 'a',
            icon: this.$q.iconSet.uploader[icon],
            flat: true,
            dense: true
          },
          on: icon === 'add' ? null : { click: fn }
        }, icon === 'add' ? this.__getInputControl(h) : null)
      }
    },

    __getInputControl (h) {
      return [
        h('input', {
          ref: 'input',
          staticClass: 'q-uploader__input overflow-hidden absolute-full',
          attrs: {
            tabindex: -1,
            type: 'file',
            title: '', // try to remove default tooltip
            accept: this.accept,
            capture: this.capture,
            ...(this.multiple === true ? { multiple: true } : {})
          },
          on: cache(this, 'input', {
            mousedown: stop, // need to stop refocus from QBtn
            change: this.__addFiles
          })
        })
      ]
    },

    __getHeader (h) {
      if (this.$scopedSlots.header !== void 0) {
        return this.$scopedSlots.header(this)
      }

      return [
        h('div', {
          staticClass: 'q-uploader__header-content flex flex-center no-wrap q-gutter-xs'
        }, [
          this.__getBtn(h, this.queuedFiles.length > 0, 'removeQueue', this.removeQueuedFiles),
          this.__getBtn(h, this.uploadedFiles.length > 0, 'removeUploaded', this.removeUploadedFiles),

          this.isUploading === true
            ? h(QSpinner, { staticClass: 'q-uploader__spinner' })
            : null,

          h('div', { staticClass: 'col column justify-center' }, [
            this.label !== void 0
              ? h('div', { staticClass: 'q-uploader__title' }, [ this.label ])
              : null,

            h('div', { staticClass: 'q-uploader__subtitle' }, [
              this.uploadSizeLabel + ' / ' + this.uploadProgressLabel
            ])
          ]),

          this.__getBtn(h, this.canAddFiles, 'add', this.pickFiles),
          this.__getBtn(h, this.hideUploadBtn === false && this.canUpload === true, 'upload', this.upload),
          this.__getBtn(h, this.isUploading, 'clear', this.abort)
        ])
      ]
    },

    __getList (h) {
      if (this.$scopedSlots.list !== void 0) {
        return this.$scopedSlots.list(this)
      }

      return this.files.map(file => h('div', {
        key: file.name,
        staticClass: 'q-uploader__file relative-position',
        class: {
          'q-uploader__file--img': this.noThumbnails !== true && file.__img !== void 0,
          'q-uploader__file--failed': file.__status === 'failed',
          'q-uploader__file--uploaded': file.__status === 'uploaded'
        },
        style: this.noThumbnails !== true && file.__img !== void 0 ? {
          backgroundImage: 'url("' + file.__img.src + '")'
        } : null
      }, [
        h('div', {
          staticClass: 'q-uploader__file-header row flex-center no-wrap'
        }, [
          file.__status === 'failed'
            ? h(QIcon, {
              staticClass: 'q-uploader__file-status',
              props: {
                name: this.$q.iconSet.type.negative,
                color: 'negative'
              }
            })
            : null,

          h('div', { staticClass: 'q-uploader__file-header-content col' }, [
            h('div', { staticClass: 'q-uploader__title' }, [ file.name ]),
            h('div', {
              staticClass: 'q-uploader__subtitle row items-center no-wrap'
            }, [
              file.__sizeLabel + ' / ' + file.__progressLabel
            ])
          ]),

          file.__status === 'uploading'
            ? h(QCircularProgress, {
              props: {
                value: file.__progress,
                min: 0,
                max: 1,
                indeterminate: file.__progress === 0
              }
            })
            : h(QBtn, {
              props: {
                round: true,
                dense: true,
                flat: true,
                icon: this.$q.iconSet.uploader[file.__status === 'uploaded' ? 'done' : 'clear']
              },
              on: {
                click: () => { this.removeFile(file) }
              }
            })
        ])
      ]))
    }
  },

  beforeDestroy () {
    this.isUploading === true && this.abort()
    this.files.length > 0 && this.__revokeImgURLs()
  },

  render (h) {
    const children = [
      h('div', {
        staticClass: 'q-uploader__header',
        class: this.colorClass
      }, this.__getHeader(h)),

      h('div', {
        staticClass: 'q-uploader__list scroll'
      }, this.__getList(h)),

      this.__getDnd(h, 'uploader')
    ]

    this.isBusy === true && children.push(
      h('div', {
        staticClass: 'q-uploader__overlay absolute-full flex flex-center'
      }, [ h(QSpinner) ])
    )

    return h('div', {
      staticClass: 'q-uploader column no-wrap',
      class: {
        'q-uploader--dark q-dark': this.isDark,
        'q-uploader--bordered': this.bordered,
        'q-uploader--square no-border-radius': this.square,
        'q-uploader--flat no-shadow': this.flat,
        'disabled q-uploader--disable': this.disable
      },
      on: this.canAddFiles === true
        ? cache(this, 'drag', { dragover: this.__onDragOver })
        : null
    }, children)
  }
})
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react'
import ResizeHandle from 'shared/components/ResizeHandle'

const {
  node,
  string,
} = PropTypes

const ResizeContainer = React.createClass({
  propTypes: {
    children: node.isRequired,
  },

  getInitialState() {
    return {
      topHeight: '60%',
      bottomHeight: '40%',
      isDragging: false,
    }
  },

  handleStopDrag() {
    this.setState({isDragging: false})
  },

  handleStartDrag() {
    this.setState({isDragging: true})
  },

  handleMouseLeave() {
    this.setState({isDragging: false})
  },

  handleDrag(e) {
    if (!this.state.isDragging) {
      return
    }

    const appHeight = parseInt(getComputedStyle(this.refs.resizeContainer).height, 10)
    // headingOffset moves the resize handle as many pixels as the page-heading is taking up.
    const headingOffset = window.innerHeight - appHeight
    const turnToPercent = 100
    const newTopPanelPercent = Math.ceil(((e.pageY - headingOffset) / (appHeight)) * turnToPercent)
    const newBottomPanelPercent = (turnToPercent - newTopPanelPercent)

    // Don't trigger a resize unless the change in size is greater than minResizePercentage
    const minResizePercentage = 0.5
    if (Math.abs(newTopPanelPercent - parseFloat(this.state.topHeight)) < minResizePercentage) {
      return
    }

    // Don't trigger a resize if the new sizes are too small
    const minTopPanelHeight = 200
    const minBottomPanelHeight = 200
    const topHeightPixels = ((newTopPanelPercent / turnToPercent) * appHeight)
    const bottomHeightPixels = ((newBottomPanelPercent / turnToPercent) * appHeight)

    if (topHeightPixels < minTopPanelHeight || bottomHeightPixels < minBottomPanelHeight) {
      return
    }

    this.setState({topHeight: `${(newTopPanelPercent)}%`, bottomHeight: `${(newBottomPanelPercent)}%`, topHeightPixels})
  },

  renderHandle() {
    const {isDragging, topHeight} = this.state
    return (
      <ResizeHandle isDragging={isDragging} onHandleStartDrag={this.handleStartDrag} top={topHeight} />
    )
  },

  render() {
    const {topHeight, topHeightPixels, bottomHeight} = this.state
    const top = React.cloneElement(this.props.children[0], {height: topHeight, heightPixels: topHeightPixels})
    const bottom = React.cloneElement(this.props.children[1], {height: bottomHeight})
    return (

        {top}
        {this.renderHandle()}
        {bottom}

    )
  },
})

const ResizeBottom = (props) => (

    {props.children}

)

ResizeBottom.propTypes = {
  children: node.isRequired,
  height: string,
}

export {ResizeBottom}

export default ResizeContainer
<commit_msg>Refactor ResizeBottom stateless component.<commit_after>import React, {PropTypes} from 'react'
import ResizeHandle from 'shared/components/ResizeHandle'

const {
  node,
  string,
} = PropTypes

const ResizeContainer = React.createClass({
  propTypes: {
    children: node.isRequired,
  },

  getInitialState() {
    return {
      topHeight: '60%',
      bottomHeight: '40%',
      isDragging: false,
    }
  },

  handleStopDrag() {
    this.setState({isDragging: false})
  },

  handleStartDrag() {
    this.setState({isDragging: true})
  },

  handleMouseLeave() {
    this.setState({isDragging: false})
  },

  handleDrag(e) {
    if (!this.state.isDragging) {
      return
    }

    const appHeight = parseInt(getComputedStyle(this.refs.resizeContainer).height, 10)
    // headingOffset moves the resize handle as many pixels as the page-heading is taking up.
    const headingOffset = window.innerHeight - appHeight
    const turnToPercent = 100
    const newTopPanelPercent = Math.ceil(((e.pageY - headingOffset) / (appHeight)) * turnToPercent)
    const newBottomPanelPercent = (turnToPercent - newTopPanelPercent)

    // Don't trigger a resize unless the change in size is greater than minResizePercentage
    const minResizePercentage = 0.5
    if (Math.abs(newTopPanelPercent - parseFloat(this.state.topHeight)) < minResizePercentage) {
      return
    }

    // Don't trigger a resize if the new sizes are too small
    const minTopPanelHeight = 200
    const minBottomPanelHeight = 200
    const topHeightPixels = ((newTopPanelPercent / turnToPercent) * appHeight)
    const bottomHeightPixels = ((newBottomPanelPercent / turnToPercent) * appHeight)

    if (topHeightPixels < minTopPanelHeight || bottomHeightPixels < minBottomPanelHeight) {
      return
    }

    this.setState({topHeight: `${(newTopPanelPercent)}%`, bottomHeight: `${(newBottomPanelPercent)}%`, topHeightPixels})
  },

  renderHandle() {
    const {isDragging, topHeight} = this.state
    return (
      <ResizeHandle isDragging={isDragging} onHandleStartDrag={this.handleStartDrag} top={topHeight} />
    )
  },

  render() {
    const {topHeight, topHeightPixels, bottomHeight} = this.state
    const top = React.cloneElement(this.props.children[0], {height: topHeight, heightPixels: topHeightPixels})
    const bottom = React.cloneElement(this.props.children[1], {height: bottomHeight})
    return (

        {top}
        {this.renderHandle()}
        {bottom}

    )
  },
})

export const ResizeBottom = ({
  height,
  children,
}) => (

    {children}

)

ResizeBottom.propTypes = {
  children: node.isRequired,
  height: string,
}

export default ResizeContainer
<|endoftext|>


<commit_before>$(function () {
    const el = $('#vis-network');
    if (!el.length) {
        return;
    }
    el.on('resize', function () {
        el.css('height', window.innerHeight - 75 + 'px');
    }());

    var filterGroups = null,
        filterShowParticipants = null,
        filterShowParticipationEdges = null,
        filterIncludeChoices = [],
        container = document.getElementById('vis-network'),
        participationEdges = el.data('participation-edges'),
        edgesSet = new vis.DataSet(el.data('edges')),
        nodesSet = new vis.DataSet(el.data('nodes')),
        nodesView = new vis.DataView(nodesSet, {
            filter: function (item) {
                if (filterGroups === null) {
                    return true;
                }
                var type = item.type;

                if (!filterShowParticipants && type === 'participant') {
                    return false;
                }
                if (type === 'choice' && $.inArray(item.bid, filterIncludeChoices) === -1) {
                    return false;
                }

                var acceptGroup = false;
                $.each(filterGroups, function (groupName, acceptedValues) {
                    var groupValue = item[groupName];
                    acceptGroup = false;

                    $.each(acceptedValues, function (key, acceptedConfiguration) {
                        var acceptedValue = acceptedConfiguration.value,
                            filterableNodes = acceptedConfiguration.nodes;

                        if ($.inArray(type, filterableNodes) === -1
                            || groupValue === acceptedValue) {
                            acceptGroup = true;
                            return false;
                        }
                    });
                    if (!acceptGroup) {
                        return false;
                    }
                });

                return acceptGroup;
            }
        });

    const hideParticipationEdges = function () {
            var edges = edgesSet.get({
                filter: function (item) {
                    return (item.type === 'participation');
                }
            });
            $.each(edges, function (key, edge) {
                edgesSet.remove(edge.id);
            });
        },
        showParticipationEdges = function () {
            hideParticipationEdges();
            $.each(participationEdges, function (key, edge) {
                edgesSet.add(edge);
            });
        };
    showParticipationEdges();

    const connectToChoice = function (nodeHuman, nodeChoice) {
        var nodeHumanId = nodeHuman.id,
            nodeChoiceId = nodeChoice.id,
            newBid = nodeChoice.bid,
            connectedNodes = network.getConnectedNodes(nodeHumanId);

        if ($.inArray(nodeChoiceId, connectedNodes) !== -1) {
            return false; //already part of this group
        }

        //remove other connections to same bid
        var connectedEdges = network.getConnectedEdges(nodeHumanId);
        $.each(connectedEdges, function (key, connectedEdgeId) {
            var connectedEdge = edgesSet.get(connectedEdgeId);
            if (connectedEdge.bid === newBid) {
                edgesSet.remove(connectedEdgeId);
            }
        });

        var newEdges = edgesSet.add({
            from: nodeHumanId,
            to: nodeChoiceId,
            bid: newBid,
            choiceId: nodeChoice.choiceId,
            color: {color: nodeChoice.color},
            dashes: true
        });
        nodesView.refresh();
        $.ajax({
            type: 'POST',
            url: '/admin/event/' + el.data('eid') + '/dependencies/change_group_assignment/' + nodeHumanId,
            data: {
                _token: el.data('token'),
                bid: newBid,
                choiceId: nodeChoice.choiceId
            },
            success: function (response) {
                if (response.success) {
                    console.log(newEdges[0]);
                    edgesSet.update({id: newEdges[0], dashes: false});
                } else {
                    location.reload();
                }
            },
            error: function () {
                location.reload();
            }
        });
        network.addEdgeMode();
    };

    var options = {
        //layout: {improvedLayout: false},
        manipulation: {
            enabled: false,
            addEdge: function (edgeData, callback) {
                if (edgeData.from === edgeData.to) {
                    return; //not adding self connections
                } else {
                    var nodeFrom = nodesSet.get(edgeData.from),
                        nodeFromType = nodeFrom.type,
                        nodeTo = nodesSet.get(edgeData.to),
                        nodeToType = nodeTo.type;

                    if ((nodeFromType !== 'choice' && nodeToType !== 'choice')
                        || (nodeFromType === 'choice' && nodeToType === 'choice')
                    ) {
                        return; //only able to connect choices but not only choices
                    }
                    if (nodeFromType === 'choice') {
                        //swap nodes in order to ensure connection has correct direction
                        var nodeTmp = nodeFrom;
                        nodeFrom = nodeTo;
                        nodeTo = nodeTmp;
                    }

                    connectToChoice(nodeFrom, nodeTo, callback);
                }
            }
        },
        nodes: {
            font: {
                face: '"Helvetica Neue", Helvetica, Arial, sans-serif',
                multi: 'md'
            }
        },
        edges: {
            font: {
                face: '"Helvetica Neue", Helvetica, Arial, sans-serif',
                multi: 'html'
            }
        }
    };
    var network = new vis.Network(
        container,
        {
            nodes: nodesView,
            edges: edgesSet
        },
        options
    );

    network.on("doubleClick", function (params) {
        if (params.nodes.length !== 1) {
            return;
        }
        var nodeId = params.nodes[0];
        if (network.isCluster(nodeId)) {
            network.openCluster(nodeId);
        } else {
            var node = nodesSet.get(nodeId),
                clusterOptionsByData;

            if (node.type !== 'choice') {
                return;
            }

            clusterOptionsByData = {
                processProperties: function (clusterOptions, childNodes) {
                    clusterOptions.label = node.label + ' [' + (childNodes.length - 1) + ']';
                    clusterOptions.color = node.color;
                    clusterOptions.shape = node.shape;
                    return clusterOptions;
                },
                clusterNodeProperties: {
                    borderWidth: 2,
                    shapeProperties: {borderDashes: [5, 2]}
                }
            };
            network.clusterByConnection(nodeId, clusterOptionsByData);
        }
    });
    network.on("selectNode", function (params) {
        if (params.nodes.length !== 1) {
            return;
        }
        var nodeId = params.nodes[0],
            node = nodesSet.get(nodeId);
    });
    $('.modes label').on('change', function () {
        var el = $(this),
            elInput = el.find('input'),
            mode = elInput.attr('id');

        if (mode === 'add-edge') {
            network.addEdgeMode();
        } else {
            network.disableEditMode();
        }
    });

    const filtersInputEls = $('.filters input'),
        filterIncludeChoicesEls = $('.filter-entities input.f'),
        updateFilterConfiguration = function () {
            filterGroups = {};
            filtersInputEls.each(function () {
                var filterEl = $(this);
                if (filterEl.prop('checked')) {
                    var property = filterEl.data('property'),
                        value = filterEl.data('value'),
                        nodes = filterEl.data('nodes');
                    if (!filterGroups[property]) {
                        filterGroups[property] = [];
                    }
                    filterGroups[property].push({
                        value: value,
                        nodes: nodes.split(',')
                    });
                }
            });
            filterShowParticipants = false;
            filterShowParticipationEdges = false;
            filterIncludeChoices = [];
            filterIncludeChoicesEls.each(function () {
                var filterEl = $(this);
                if (filterEl.prop('checked')) {
                    var type = filterEl.data('type'),
                        bid = filterEl.data('bid');

                    switch (type) {
                        case 'participation-edges':
                            filterShowParticipationEdges = true;
                            break;
                        case 'participant':
                            filterShowParticipants = true;
                            break;
                        case 'choice':
                            filterIncludeChoices.push(bid);
                            break;
                    }
                }
            });
            nodesView.refresh();
        };
    filtersInputEls.on('change', updateFilterConfiguration);
    filterIncludeChoicesEls.on('change', updateFilterConfiguration);

    $('#btnShowParticipationEdges').on('change', function () {
        if ($(this).prop('checked')) {
            showParticipationEdges();
        } else {
            hideParticipationEdges();
        }
    });
});<commit_msg>Resetting mode when filtering<commit_after>$(function () {
    const el = $('#vis-network');
    if (!el.length) {
        return;
    }
    el.on('resize', function () {
        el.css('height', window.innerHeight - 75 + 'px');
    }());

    var filterGroups = null,
        filterShowParticipants = null,
        filterShowParticipationEdges = null,
        filterIncludeChoices = [],
        container = document.getElementById('vis-network'),
        participationEdges = el.data('participation-edges'),
        edgesSet = new vis.DataSet(el.data('edges')),
        nodesSet = new vis.DataSet(el.data('nodes')),
        nodesView = new vis.DataView(nodesSet, {
            filter: function (item) {
                if (filterGroups === null) {
                    return true;
                }
                var type = item.type;

                if (!filterShowParticipants && type === 'participant') {
                    return false;
                }
                if (type === 'choice' && $.inArray(item.bid, filterIncludeChoices) === -1) {
                    return false;
                }

                var acceptGroup = false;
                $.each(filterGroups, function (groupName, acceptedValues) {
                    var groupValue = item[groupName];
                    acceptGroup = false;

                    $.each(acceptedValues, function (key, acceptedConfiguration) {
                        var acceptedValue = acceptedConfiguration.value,
                            filterableNodes = acceptedConfiguration.nodes;

                        if ($.inArray(type, filterableNodes) === -1
                            || groupValue === acceptedValue) {
                            acceptGroup = true;
                            return false;
                        }
                    });
                    if (!acceptGroup) {
                        return false;
                    }
                });

                return acceptGroup;
            }
        });

    const hideParticipationEdges = function () {
            var edges = edgesSet.get({
                filter: function (item) {
                    return (item.type === 'participation');
                }
            });
            $.each(edges, function (key, edge) {
                edgesSet.remove(edge.id);
            });
        },
        showParticipationEdges = function () {
            hideParticipationEdges();
            $.each(participationEdges, function (key, edge) {
                edgesSet.add(edge);
            });
        };
    showParticipationEdges();

    const connectToChoice = function (nodeHuman, nodeChoice) {
        var nodeHumanId = nodeHuman.id,
            nodeChoiceId = nodeChoice.id,
            newBid = nodeChoice.bid,
            connectedNodes = network.getConnectedNodes(nodeHumanId);

        if ($.inArray(nodeChoiceId, connectedNodes) !== -1) {
            return false; //already part of this group
        }

        //remove other connections to same bid
        var connectedEdges = network.getConnectedEdges(nodeHumanId);
        $.each(connectedEdges, function (key, connectedEdgeId) {
            var connectedEdge = edgesSet.get(connectedEdgeId);
            if (connectedEdge.bid === newBid) {
                edgesSet.remove(connectedEdgeId);
            }
        });

        var newEdges = edgesSet.add({
            from: nodeHumanId,
            to: nodeChoiceId,
            bid: newBid,
            choiceId: nodeChoice.choiceId,
            color: {color: nodeChoice.color},
            dashes: true
        });
        nodesView.refresh();
        $.ajax({
            type: 'POST',
            url: '/admin/event/' + el.data('eid') + '/dependencies/change_group_assignment/' + nodeHumanId,
            data: {
                _token: el.data('token'),
                bid: newBid,
                choiceId: nodeChoice.choiceId
            },
            success: function (response) {
                if (response.success) {
                    console.log(newEdges[0]);
                    edgesSet.update({id: newEdges[0], dashes: false});
                } else {
                    location.reload();
                }
            },
            error: function () {
                location.reload();
            }
        });
        network.addEdgeMode();
    };

    var options = {
        //layout: {improvedLayout: false},
        manipulation: {
            enabled: false,
            addEdge: function (edgeData, callback) {
                if (edgeData.from === edgeData.to) {
                    return; //not adding self connections
                } else {
                    var nodeFrom = nodesSet.get(edgeData.from),
                        nodeFromType = nodeFrom.type,
                        nodeTo = nodesSet.get(edgeData.to),
                        nodeToType = nodeTo.type;

                    if ((nodeFromType !== 'choice' && nodeToType !== 'choice')
                        || (nodeFromType === 'choice' && nodeToType === 'choice')
                    ) {
                        return; //only able to connect choices but not only choices
                    }
                    if (nodeFromType === 'choice') {
                        //swap nodes in order to ensure connection has correct direction
                        var nodeTmp = nodeFrom;
                        nodeFrom = nodeTo;
                        nodeTo = nodeTmp;
                    }

                    connectToChoice(nodeFrom, nodeTo, callback);
                }
            }
        },
        nodes: {
            font: {
                face: '"Helvetica Neue", Helvetica, Arial, sans-serif',
                multi: 'md'
            }
        },
        edges: {
            font: {
                face: '"Helvetica Neue", Helvetica, Arial, sans-serif',
                multi: 'html'
            }
        }
    };
    var network = new vis.Network(
        container,
        {
            nodes: nodesView,
            edges: edgesSet
        },
        options
    );

    network.on("doubleClick", function (params) {
        if (params.nodes.length !== 1) {
            return;
        }
        var nodeId = params.nodes[0];
        if (network.isCluster(nodeId)) {
            network.openCluster(nodeId);
        } else {
            var node = nodesSet.get(nodeId),
                clusterOptionsByData;

            if (node.type !== 'choice') {
                return;
            }

            clusterOptionsByData = {
                processProperties: function (clusterOptions, childNodes) {
                    clusterOptions.label = node.label + ' [' + (childNodes.length - 1) + ']';
                    clusterOptions.color = node.color;
                    clusterOptions.shape = node.shape;
                    return clusterOptions;
                },
                clusterNodeProperties: {
                    borderWidth: 2,
                    shapeProperties: {borderDashes: [5, 2]}
                }
            };
            network.clusterByConnection(nodeId, clusterOptionsByData);
        }
    });
    network.on("selectNode", function (params) {
        if (params.nodes.length !== 1) {
            return;
        }
        var nodeId = params.nodes[0],
            node = nodesSet.get(nodeId);
    });
    $('.modes label').on('change', function () {
        var el = $(this),
            elInput = el.find('input'),
            mode = elInput.attr('id');

        if (mode === 'add-edge') {
            network.addEdgeMode();
        } else {
            network.disableEditMode();
        }
    });

    const filtersInputEls = $('.filters input'),
        filterIncludeChoicesEls = $('.filter-entities input.f'),
        updateFilterConfiguration = function () {
            filterGroups = {};
            filtersInputEls.each(function () {
                var filterEl = $(this);
                if (filterEl.prop('checked')) {
                    var property = filterEl.data('property'),
                        value = filterEl.data('value'),
                        nodes = filterEl.data('nodes');
                    if (!filterGroups[property]) {
                        filterGroups[property] = [];
                    }
                    filterGroups[property].push({
                        value: value,
                        nodes: nodes.split(',')
                    });
                }
            });
            filterShowParticipants = false;
            filterShowParticipationEdges = false;
            filterIncludeChoices = [];
            filterIncludeChoicesEls.each(function () {
                var filterEl = $(this);
                if (filterEl.prop('checked')) {
                    var type = filterEl.data('type'),
                        bid = filterEl.data('bid');

                    switch (type) {
                        case 'participation-edges':
                            filterShowParticipationEdges = true;
                            break;
                        case 'participant':
                            filterShowParticipants = true;
                            break;
                        case 'choice':
                            filterIncludeChoices.push(bid);
                            break;
                    }
                }
            });
            nodesView.refresh();
            $('#display').click();
        };
    filtersInputEls.on('change', updateFilterConfiguration);
    filterIncludeChoicesEls.on('change', updateFilterConfiguration);

    $('#btnShowParticipationEdges').on('change', function () {
        if ($(this).prop('checked')) {
            showParticipationEdges();
        } else {
            hideParticipationEdges();
        }
    });
});<|endoftext|>


<commit_before>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
//
//= require jquery
//= require jquery_ujs
//= require_tree .<commit_msg>added jquery-ui for calender input<commit_after>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
//
//= require jquery
//= require jquery_ujs
//= require jquery-ui
//= require_tree .<|endoftext|>


<commit_before>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery.turbolinks
//= require jquery_ujs
//= require turbolinks
//= require vendor/velocity.min
//= require vendor/jquery.dynatable
//= require vendor/jquery.sticky
//= require vendor/tipsy
//= require vendor/quill.min
//= require cookies_eu
//= require vendor/pickadate/picker
//= require vendor/pickadate/picker.date
//= require vendor/pickadate/picker.time

//= require ui
// require menu
//= require_tree .
<commit_msg>UI.js<commit_after>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery.turbolinks
//= require jquery_ujs
//= require turbolinks
//= require vendor/velocity.min
//= require vendor/jquery.dynatable
//= require vendor/jquery.sticky
//= require vendor/tipsy
//= require vendor/quill.min
//= require cookies_eu
//= require vendor/pickadate/picker
//= require vendor/pickadate/picker.date
//= require vendor/pickadate/picker.time

//= require ui
<|endoftext|>


<commit_before>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .
<commit_msg>Add jquery to asset pipeline<commit_after>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery-ui
//= require jquery_ujs
//= require turbolinks
//= require_tree .
<|endoftext|>


<commit_before>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
//
//= require jquery
//= require jquery_ujs
//= require fancybox
//= require_tree .

$(document).ready(function() {
  $(document).on("click", ".banner_remover", function() {
    $("." + $(this).data("banner-class")).remove();
  });
});

$(document).ready(function () {
  if (!$('input').hasClass("multiclick")) {
    $('form').submit(function() {
      $("input[type='submit']", this).attr("disabled", "disabled");
      $("input[type='submit']", this).val("Please wait...");
    });
  }
});

/* Generic sorting dataTable */
$(document).ready(function() {
  $(".sortable").each(function() {
    $(this).dataTable({
      "bInfo": false,
      "bPaginate": false
    });
  });
});
<commit_msg>remove the 'search' box on 'sortable' tables<commit_after>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
//
//= require jquery
//= require jquery_ujs
//= require fancybox
//= require_tree .

$(document).ready(function() {
  $(document).on("click", ".banner_remover", function() {
    $("." + $(this).data("banner-class")).remove();
  });
});

$(document).ready(function () {
  if (!$('input').hasClass("multiclick")) {
    $('form').submit(function() {
      $("input[type='submit']", this).attr("disabled", "disabled");
      $("input[type='submit']", this).val("Please wait...");
    });
  }
});

/* Generic sorting dataTable */
$(document).ready(function() {
  $(".sortable").each(function() {
    $(this).dataTable({
      "bFilter": false,
      "bInfo": false,
      "bPaginate": false
    });
  });
});
<|endoftext|>


<commit_before>/**
 * Loads fake API when required.
 * Bootstraps application only when not running tests.
 */

define({
  load: function(name, req, onLoad, config) {

    var that = this;
    var loadApplication = function () {
      if (window.jasmine) {
        // Don't initialise app when running unit tests
        onLoad.call(that);
      } else {
        // Load controller for this page
        var controller = $('#wrapper').data('controller');
        req([controller], function (controller) {
          onLoad.call(that);
        });
      }
    }

    var backdropUrl = $('#wrapper').data('backdrop-url');
    if (!window.jasmine && backdropUrl && backdropUrl.indexOf('//fakeapi') == -1) {
      // use real API
      loadApplication();
    } else {
      // use fake API
      req(['fakeapi'], function (fakeapi) {
        loadApplication();
      });
    }
  }
});
<commit_msg>Remove application.js - no more in use<commit_after><|endoftext|>


<commit_before>//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require bootstrap-sprockets
//= require_tree .

document.addEventListener("turbolinks:load", function() {
  $('.archive').click(function() {
    Turbolinks.visit('/notifications/'+$(this).val()+'/archive'+location.search)
  });
  $('.unarchive').click(function() {
    Turbolinks.visit('/notifications/'+$(this).val()+'/unarchive'+location.search)
  });
  $('.toggle-star').click(function() {
    $(this).toggleClass("star-active star-inactive")
    $.get('/notifications/'+$(this).data('id')+'/star')
  });
  $('a.sync').on('click', function() {
    $(this).find('.octicon').toggleClass('spinning')
  });
  recoverPreviousCursorPosition()
});

document.addEventListener("turbolinks:before-cache", function() {
  $('td.current').removeClass("current");
});

// Add shortcut events only once
$(document).ready(enableKeyboardShortcuts);

$(document).on('click', '[data-toggle="offcanvas"]', function () {
  $('.row-offcanvas').toggleClass('active')
});

if(!('ontouchstart' in window))
{
  $(function () {
    $('[data-toggle="tooltip"]').tooltip()
  })
}

function enableKeyboardShortcuts() {
  window.row_index = 1

  $(document).keydown(function(e) {
    var shortcutFunction = shortcuts[e.which]
    if (shortcutFunction) { shortcutFunction(e) }
  });
}

var shortcuts = {
  74:  cursorDown,      // j
  75:  cursorUp,        // k
  83:  toggleStar,      // s
  89:  archive,         // y
  13:  openCurrentLink, // Enter
  79:  openCurrentLink, // o
  191: openModal,       // ?
  190: sync,            // .
  82:  sync             // r
}

function cursorDown() {
  current = $('td.current');
  next = $(current).parent().next();
  if(next.length > 0) {
    $(current).removeClass("current");
    $(next).find('td').first().addClass("current");
    row_index += 1;
  }
}

function cursorUp() {
  current = $('td.current');
  prev = $(current).parent().prev();
  if(prev.length > 0) {
    $(current).removeClass("current");
    $(prev).find('td').first().addClass("current");
    row_index -= 1;
  }
}

function archive() {
  clickCurrentRow('.archive')
}

function toggleStar() {
  clickCurrentRow('.toggle-star')
}

function openModal() {
  $("#help-box").modal();
}

function openCurrentLink(e) {
  e.preventDefault(e);
  $('td.current').parent().find('.link')[0].click();
}

function sync() {
  $("a.sync").click();
}

function clickCurrentRow(cssClass) {
  $('td.current').parent().find(cssClass).click();
}

function recoverPreviousCursorPosition() {
  row_index = Math.min(row_index, $(".table-notifications tr").length);
  row_index = Math.max(row_index, 1);
  $(".table-notifications tbody tr:nth-child(" + row_index + ")").first().find("td").first().addClass("current");
}
<commit_msg>Reduce more js duplication<commit_after>//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require bootstrap-sprockets
//= require_tree .

document.addEventListener("turbolinks:load", function() {
  $('.archive').click(function() {
    loadTurbolinksArchiveURL(this, 'archive')
  });
  $('.unarchive').click(function() {
    loadTurbolinksArchiveURL(this, 'unarchive')
  });
  $('.toggle-star').click(function() {
    $(this).toggleClass("star-active star-inactive")
    $.get('/notifications/'+$(this).data('id')+'/star')
  });
  $('a.sync').on('click', function() {
    $(this).find('.octicon').toggleClass('spinning')
  });
  recoverPreviousCursorPosition()
});

document.addEventListener("turbolinks:before-cache", function() {
  $('td.current').removeClass("current");
});

// Add shortcut events only once
$(document).ready(enableKeyboardShortcuts);

$(document).on('click', '[data-toggle="offcanvas"]', function () {
  $('.row-offcanvas').toggleClass('active')
});

if(!('ontouchstart' in window))
{
  $(function () {
    $('[data-toggle="tooltip"]').tooltip()
  })
}

function enableKeyboardShortcuts() {
  window.row_index = 1

  $(document).keydown(function(e) {
    var shortcutFunction = shortcuts[e.which]
    if (shortcutFunction) { shortcutFunction(e) }
  });
}

var shortcuts = {
  74:  cursorDown,      // j
  75:  cursorUp,        // k
  83:  toggleStar,      // s
  89:  archive,         // y
  13:  openCurrentLink, // Enter
  79:  openCurrentLink, // o
  191: openModal,       // ?
  190: sync,            // .
  82:  sync             // r
}

function cursorDown() {
  current = $('td.current');
  next = $(current).parent().next();
  if(next.length > 0) {
    $(current).removeClass("current");
    $(next).find('td').first().addClass("current");
    row_index += 1;
  }
}

function cursorUp() {
  current = $('td.current');
  prev = $(current).parent().prev();
  if(prev.length > 0) {
    $(current).removeClass("current");
    $(prev).find('td').first().addClass("current");
    row_index -= 1;
  }
}

function archive() {
  clickCurrentRow('.archive')
}

function toggleStar() {
  clickCurrentRow('.toggle-star')
}

function openModal() {
  $("#help-box").modal();
}

function openCurrentLink(e) {
  e.preventDefault(e);
  $('td.current').parent().find('.link')[0].click();
}

function sync() {
  $("a.sync").click();
}

function clickCurrentRow(cssClass) {
  $('td.current').parent().find(cssClass).click();
}

function recoverPreviousCursorPosition() {
  row_index = Math.min(row_index, $(".table-notifications tr").length);
  row_index = Math.max(row_index, 1);
  $(".table-notifications tbody tr:nth-child(" + row_index + ")").first().find("td").first().addClass("current");
}

function loadTurbolinksArchiveURL(link, route) {
  Turbolinks.visit('/notifications/'+$(link).val()+'/'+route+location.search)
}
<|endoftext|>


<commit_before>// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery-2.2.2.js
//= require jquery_ujs
//= require bootstrap
//= require masonry-4.0.0
//= require static_pages<commit_msg>don't require masonry js on all pages; only on user#show<commit_after>// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery-2.2.2.js
//= require jquery_ujs
//= require bootstrap
//= require static_pages<|endoftext|>


<commit_before>// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
//= require underscore
//= require jquery
//= require jquery_ujs
//= require jquery.markitup
//= require jquery.textcomplete
//= require d3
//= require markitup-html
//= require autocompleter
//= require emoji
//= require redcursor_app
//= require notifications
//= require channels
//= require search
//= require react
//= require react_ujs
//= require redcursor-app
<commit_msg>Remove react_ujs require<commit_after>// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
//= require underscore
//= require jquery
//= require jquery_ujs
//= require jquery.markitup
//= require jquery.textcomplete
//= require d3
//= require markitup-html
//= require autocompleter
//= require emoji
//= require redcursor_app
//= require notifications
//= require channels
//= require search
//= require react
//= require redcursor-app
<|endoftext|>


<commit_before>/*
  The following comments are parsed by Gulp include
  (https://www.npmjs.com/package/gulp-include) which uses
  Sprockets-style (https://github.com/sstephenson/sprockets)
  directives to concatenate multiple Javascript files into one.
*/
//= include ../../../node_modules/govuk_frontend_toolkit/javascripts/govuk/analytics/analytics.js
//= include ../../../node_modules/govuk_frontend_toolkit/javascripts/govuk/analytics/google-analytics-universal-tracker.js
//= include ../../../node_modules/govuk_frontend_toolkit/javascripts/vendor/polyfills/bind.js
//= include ../../../bower_components/jquery/dist/jquery.js
//= include ../../../bower_components/hogan/web/builds/3.0.2/hogan-3.0.2.js
//= include ../../../bower_components/digitalmarketplace-frontend-toolkit/toolkit/javascripts/list-entry.js
//= include ../../../bower_components/digitalmarketplace-frontend-toolkit/toolkit/javascripts/word-counter.js
//= include ../../../bower_components/digitalmarketplace-frontend-toolkit/toolkit/javascripts/validation.js
//= include ../../../node_modules/govuk_frontend_toolkit/javascripts/govuk/selection-buttons.js
//= include _selection-buttons.js
//= include _analytics.js

(function(GOVUK, GDM) {

  "use strict";

  var module;

  if (
    (GDM.debug = !window.location.href.match(/gov.uk/) && !window.jasmine)
  ) {
    console.log(
      "%cDebug mode %cON",
      "color:#550; background:yellow; font-size: 11pt",
      "color:yellow; background: #550;font-size:11pt"
    );
    console.time("Modules loaded");
  }

  // Initialise our modules
  for (module in GDM) {

    if (GDM.debug && module !== "debug") {
      console.log(
        "%cLoading module %c" + module,
        "color:#6a6; background:#dfd; font-size: 11pt",
        "color:#dfd; background:green; font-size: 11pt"
      );
    }

    if ("function" === typeof GDM[module].init) {
      // If a module has an init() method then we want that to be called here
      GDM[module].init();
    } else if ("function" === typeof GDM[module]) {
      // If a module doesn't have an interface then call it directly
      GDM[module]();
    }

  }

  GOVUK.GDM = GDM;

  if (GDM.debug) console.timeEnd("Modules loaded");

}).apply(this, [GOVUK||{}, GOVUK.GDM||{}]);
<commit_msg>Stub out console object for older browsers<commit_after>/*
  The following comments are parsed by Gulp include
  (https://www.npmjs.com/package/gulp-include) which uses
  Sprockets-style (https://github.com/sstephenson/sprockets)
  directives to concatenate multiple Javascript files into one.
*/
//= include ../../../node_modules/govuk_frontend_toolkit/javascripts/govuk/analytics/analytics.js
//= include ../../../node_modules/govuk_frontend_toolkit/javascripts/govuk/analytics/google-analytics-universal-tracker.js
//= include ../../../node_modules/govuk_frontend_toolkit/javascripts/vendor/polyfills/bind.js
//= include ../../../bower_components/jquery/dist/jquery.js
//= include ../../../bower_components/hogan/web/builds/3.0.2/hogan-3.0.2.js
//= include ../../../bower_components/digitalmarketplace-frontend-toolkit/toolkit/javascripts/list-entry.js
//= include ../../../bower_components/digitalmarketplace-frontend-toolkit/toolkit/javascripts/word-counter.js
//= include ../../../bower_components/digitalmarketplace-frontend-toolkit/toolkit/javascripts/validation.js
//= include ../../../node_modules/govuk_frontend_toolkit/javascripts/govuk/selection-buttons.js
//= include _selection-buttons.js
//= include _analytics.js

(function(GOVUK, GDM) {

  "use strict";

  var module;

  if(typeof console === 'undefined') {
    console = {
      log: function () {},
      time: function () {},
      timeEnd: function () {}
    };
  }

  if (
    (GDM.debug = !window.location.href.match(/gov.uk/) && !window.jasmine)
  ) {
    console.log(
      "%cDebug mode %cON",
      "color:#550; background:yellow; font-size: 11pt",
      "color:yellow; background: #550;font-size:11pt"
    );
    console.time("Modules loaded");
  }

  // Initialise our modules
  for (module in GDM) {

    if (GDM.debug && module !== "debug") {
      console.log(
        "%cLoading module %c" + module,
        "color:#6a6; background:#dfd; font-size: 11pt",
        "color:#dfd; background:green; font-size: 11pt"
      );
    }

    if ("function" === typeof GDM[module].init) {
      // If a module has an init() method then we want that to be called here
      GDM[module].init();
    } else if ("function" === typeof GDM[module]) {
      // If a module doesn't have an interface then call it directly
      GDM[module]();
    }

  }

  GOVUK.GDM = GDM;

  if (GDM.debug) console.timeEnd("Modules loaded");

}).apply(this, [GOVUK||{}, GOVUK.GDM||{}]);
<|endoftext|>