<commit_before>import Users from 'collections/users'
import ProcessingPipelines from 'collections/processingpipelines'
import SpaceGroups from 'collections/spacegroups.js'
import CentringMethodList from 'utils/centringmethods.js'
import AnomalousList from 'utils/anoms.js'
import ExperimentKindsList from 'utils/experimentkinds.js'
import DistinctProteins from 'modules/shipment/collections/distinctproteins'
import ContainerRegistry from 'modules/shipment/collections/containerregistry'
import ContainerTypes from 'modules/shipment/collections/containertypes'
import SampleGroups from 'collections/samplegroups'
import ImagingImager from 'modules/imaging/collections/imagers'
import ImagingSchedules from 'modules/imaging/collections/schedules'
import ImagingScreens from 'modules/imaging/collections/screens'
import ImagingScheduleComponents from 'modules/imaging/collections/schedulecomponents'
import { mapGetters } from 'vuex'
import Sample from 'models/sample'
import SampleGroupSamples from "collections/samplegroupsamples";
import ContainerQueue from "modules/shipment/models/containerqueue";
import { omit } from 'lodash'

const INITIAL_CONTAINER_TYPE = {
  CONTAINERTYPEID: 0,
  CAPACITY: 0,
  DROPPERWELLX: null,
  DROPPERWELLY: null,
  DROPHEIGHT: null,
  DROPWIDTH: null,
  WELLDROP: -1,
  WELLPERROW: null,
}

export default {
  data() {
    return {
      anomalousList: AnomalousList.list,

      centringMethods: CentringMethodList.list,
      containerType: {},
      containerTypes: [],
      containerTypesCollection: new ContainerTypes(),
      containerRegistryCollection: new ContainerRegistry(),
      containerRegistry: [],
      containerRegistryId: '',

      experimentTypes: [],
      experimentTypesCollection: null,
      experimentKindList: [],

      imagingImagers: [],
      imagingCollections: null,
      imagingSchedules: [],
      imagingSchedulesCollection: null,
      imagingScheduleComponents: [],
      imagingScheduleComponentsCollection: null,
      imagingScreens: [],
      imagingScreensCollections: null,

      processingPipeline: '',
      processingPipelines: [],

      proteins: [],
      proteinsCollection: new DistinctProteins(null, { state: { pageSize: 9999 }, queryParams: { per_page: 9999 } }),

      users: [],
      usersCollection: null,

      sampleGroupsCollection: null,
      sampleGroups: [],
      spaceGroups: [],
      spaceGroupsCollection: null,
      sampleGroupSamples: [],
      sampleGroupInputDisabled: false
    }
  },
  methods: {
    async getUsers() {
      this.usersCollection = new Users(null, { state: { pageSize: 9999 }})
      this.usersCollection.queryParams.all = 1
      this.usersCollection.queryParams.pid = this.$store.state.proposal.proposalModel.get('PROPOSALID')

      const result = await this.$store.dispatch('getCollection', this.usersCollection)
      this.users = result.toJSON()
      // Set plate owner to current user
      this.PERSONID = this.$store.state.user.personId
    },
    async getProcessingPipelines() {
      let processingPipelinesCollection = new ProcessingPipelines()

      processingPipelinesCollection.queryParams.pipelinestatus = 'optional'
      processingPipelinesCollection.queryParams.category = 'processing'

      const result = await this.$store.dispatch('getCollection', processingPipelinesCollection)
      this.processingPipelines = result.toJSON()
    },
    async getProteins() {
      // If we want to only allow valid samples
      if (app.options.get('valid_components') && !app.staff) {
        this.proteinsCollection.queryParams.external = 1
      }

      this.proteinsCollection.queryParams.SAFETYLEVEL = 'ALL'

      const result = await this.$store.dispatch('getCollection', this.proteinsCollection)
      this.proteins = result.toJSON()
    },
    async getContainerRegistry() {
      this.containerRegistryCollection = new ContainerRegistry(null, { state: { pageSize: 9999 }})
      const result = await this.$store.dispatch('getCollection', this.containerRegistryCollection)
      this.containerRegistry = [{ CONTAINERREGISTRYID: null, BARCODE: ""}, ...result.toJSON()]
    },
    async getContainerTypes() {
      this.containerFilter = [this.$store.state.proposal.proposalType]

      const result = await this.$store.dispatch('getCollection', this.containerTypesCollection)
      this.containerTypes = result.toJSON()
      // Do we have valid start state?
      if (this.containerTypes.length) {
        let initialContainerType = result.findWhere({PROPOSALTYPE: this.containerFilter[0]})
        this.CONTAINERTYPEID = initialContainerType ? initialContainerType.get('CONTAINERTYPEID') : ''
      }

      if (this.container) {
        let containerTypeModel = result.findWhere({NAME: this.container.CONTAINERTYPE})

        if (containerTypeModel) {
          this.containerType = Object.assign(INITIAL_CONTAINER_TYPE, containerTypeModel.toJSON())
        }
      }
    },
    formatExperimentKindList() {
      let experimentKindList = []
      for (const [key, value] of Object.entries(ExperimentKindsList.list)) {
        experimentKindList.push({ value, text: key })
      }

      this.experimentKindList = experimentKindList.filter(experimentKind => experimentKind.value)
    },
    async getSampleGroups() {
      this.sampleGroupsCollection = new SampleGroups(null, { state: { pageSize: 9999 }})

      const result = await this.$store.dispatch('getCollection', this.sampleGroupsCollection)

      this.sampleGroups = result.toJSON().map((group, index) => ({
        value: group.BLSAMPLEGROUPID,
        text: group.NAME || `Unknown Sample Group ${index}`
      }))
      this.sampleGroupInputDisabled = false
    },
    async getImagingCollections() {
      this.imagingCollections = new ImagingImager(null, { state: { pageSize: 9999 } })

      const result = await this.$store.dispatch('getCollection', this.imagingCollections)
      this.imagingImagers = result.toJSON()
    },
    async getImagingScheduleCollections() {
      this.imagingSchedulesCollection = new ImagingSchedules(null, { state: { pageSize: 9999 } })

      const result = await this.$store.dispatch('getCollection', this.imagingSchedulesCollection)
      this.imagingSchedules = result.toJSON()
    },
    async getImagingScreensCollections() {
      this.imagingScreensCollection = new ImagingScreens(null, { state: { pageSize: 9999 } })

      const result = await this.$store.dispatch('getCollection', this.imagingScreensCollection)
      this.imagingScreens = result.toJSON()
    },
    async getImagingScheduleComponentsCollection() {
      this.imagingScheduleComponentsCollection = new ImagingScheduleComponents(null, { state: { pageSize: 9999 } })
      this.imagingScheduleComponentsCollection.queryParams.shid = this.selectedSchedule.SCHEDULEID

      const result = await this.$store.dispatch('getCollection', this.imagingScheduleComponentsCollection)
      this.imagingScheduleComponents = result.toJSON()
    },
    async getSpaceGroupsCollection() {
      this.spaceGroupsCollection = new SpaceGroups(null, { state: { pageSize: 9999 } })
      if (!this.SPACEGROUP) {
        this.spaceGroupsCollection.queryParams.ty = this.containerGroup
      }

      const result = await this.$store.dispatch('getCollection', this.spaceGroupsCollection)
      this.spaceGroups = result.toJSON()
    },
    // Clone the next free row based on the current row
    onCloneSample(sampleLocation) {
      // Make sure we are using numbers for locations
      let location = +sampleLocation
      // Take the next sample in the list and copy this data
      // Locations should be in range 1..samples.length-1 (can't clone last sample in list)
      if (location < 0 || location > (this.samples.length-1)) return

      // Sample to be copied and next index
      let nextSampleIndex = -1
      // Recreate current behaviour - find the next non-zero protein id
      // This means you can click any row icon and it will fill whatever is the next empty link item based on protein id/valid acronym
      for (let i = location; i < this.samples.length; i++) {
        if (+this.samples[i]['PROTEINID'] < 0) {
          nextSampleIndex = i
          break
        }
      }

      this.cloneSample(location, nextSampleIndex)
    },
    // Clear row for a single row in the sample table
    onClearSample(sampleLocation) {
      let location = +sampleLocation
      // Clear the row for this location
      // Locations should be in range 1..samples.length
      if (location < 0 || location > this.samples.length) return
      // The location is one more than the sample index
      this.$store.commit('samples/clearSample', location)
    },
    // Take first entry (or index) and clone all rows
    onCloneContainer(sampleIndex=0) {
      for (let i = 0; i < this.samples.length; i++) {
        this.cloneSample(sampleIndex, i)
      }
    },
    // Remove all sample information from every row
    onClearContainer() {
      for (let i = 0; i < this.samples.length; i++) {
        this.$store.commit('samples/clearSample', i)
      }
    },
    // When cloning, take the last digits and pad the new samples names
    // So if 1: sample-01, 2: will equal sample-02 etc.
    generateSampleName(name, startAtIndex) {
      if (!name) return null

      let name_base = name.replace(/([\d]+)$/, '')
      let digits = name.match(/([\d]+)$/)
      let number_pad = (digits && digits.length > 1) ? digits[1].length : 0

      return name_base+((startAtIndex).toString().padStart(number_pad, '0'))
    },
    // Save the sample to the server via backbone model
    // Location should be the sample LOCATION
    async onSaveSample(location) {
      const result = await this.$refs.containerForm.validate()
      if (result) {
        await this.saveSample(location)
        const samplesRef = this.$refs.samples
        samplesRef.$refs[`sample-row-${location}`][0].closeSampleEditing()
      }
      else {
        this.$store.commit('notifications/addNotification', { message: 'Sample data is invalid, please check the form', level: 'error'})
      }
    },
    async saveSample(location) {
      let sampleIndex = +location
      // Create a new Sample Model, so it uses the BLSAMPLEID to check for post, update etc
      let sampleModel = new Sample(omit(this.samples[sampleIndex], 'STRATEGYOPTION'))

      console.log({ sampleModel, sampleData: this.samples[sampleIndex] })

      const result = await this.$store.dispatch('saveModel', { model: sampleModel })

      if (!this.samples[sampleIndex]['BLSAMPLEID'])
        this.$store.commit('samples/updateSamplesField', {
          path: `samples/${sampleIndex}/BLSAMPLEID`,
          value: result.get('BLSAMPLEID')
        })
    },
    getRowColDrop(pos) {
      let well = this.containerType.WELLDROP > -1 ? 1 : 0
      let dropTotal = (this.containerType.DROPPERWELLX * this.containerType.DROPPERWELLY) - well

      const wellPosition = Math.floor((parseInt(pos) - 1) / dropTotal);
      const drop = ((pos - 1) % dropTotal) + 1;

      const col = wellPosition % this.containerType.WELLPERROW;
      const row = Math.floor(wellPosition / this.containerType.WELLPERROW);

      return { row: row, col: col, drop: drop, pos: pos }
    },
    // While updating the sample locations during the cloning, the update will stop is one of the form field is invalid.
    async onCloneColumn(location) {
      let sampleIndex = +location - 1
      let sourceCoordinates = this.getRowColDrop(location)

      for (let i = 0; i < this.samples.length; i++) {
        // We are only cloning samples that come after this one - so skip any with a lower index
        if (i > sampleIndex) {
          let targetCoordinates = this.getRowColDrop(this.samples[i].LOCATION)

          if (targetCoordinates['drop'] === sourceCoordinates['drop'] && targetCoordinates['col'] === sourceCoordinates['col']) {
            this.cloneSample(sampleIndex, i)
            this.sampleLocation = i

            await this.$nextTick()
            const locationValid = await this.$refs.containerForm.validate();

            if (!locationValid) {
              break
            } else {
              this.$store.commit('samples/updateSamplesField', {
                path: `samples/${sampleIndex}/VALID`,
                value: 1
              })
            }
          }
        }
      }
    },
    // While updating the sample locations during the cloning, the update will stop is one of the form field is invalid.
    async onCloneRow(location) {
      let sampleIndex = +location - 1
      let sourceCoordinates = this.getRowColDrop(location)

      for (let i = 0; i < this.samples.length; i++) {
        // We are only cloning samples that come after this one - so skip any with a lower index
        if (i > sampleIndex) {
          let targetCoordinates = this.getRowColDrop(this.samples[i].LOCATION)

          if (targetCoordinates['drop'] === sourceCoordinates['drop'] && targetCoordinates['row'] === sourceCoordinates['row']) {
            this.cloneSample(sampleIndex, i)
            this.sampleLocation = i

            await this.$nextTick()
            const locationValid = await this.$refs.containerForm.validate();

            if (!locationValid) {
              break
            } else {
              this.$store.commit('samples/updateSamplesField', {
                path: `samples/${sampleIndex}/VALID`,
                value: 1
              })
            }
          }
        }
      }
    },
    cloneSample(sourceIndex, targetIndex) {
      if (targetIndex < 0 || targetIndex >= this.samples.length) return false
      if (sourceIndex < 0 || sourceIndex >= this.samples.length) return false

      let sourceSample = this.samples[sourceIndex]
      if (sourceSample.PROTEINID < 0) return false

      let baseName = this.samples[sourceIndex].NAME
      let sampleClone = { ...this.samples[targetIndex], ...this.samples[sourceIndex] }
      sampleClone.LOCATION = (targetIndex + 1).toString()
      sampleClone.NAME = this.generateSampleName(baseName, targetIndex+1)
      this.$store.commit('samples/setSample', { index: targetIndex, data: sampleClone })
    },
    // Reset the validation for the field when an input is edited
    resetFormValidation() {
      requestAnimationFrame(() => {
        this.$refs.containerForm.reset()
      })
    },
    async fetchSampleGroupSamples() {
      const sampleGroupCollection = new SampleGroups(null, { state: { pageSize: 9999 } })

      const result = await this.$store.dispatch('getCollection', sampleGroupCollection)
      const sampleGroups = result.toJSON()

      let sampleGroupSamples = []
      let sampleGroupSamplesPromise = []

      for (let i = 0; i < sampleGroups.length; i++) {
        const sampleGroupSamplesCollection = new SampleGroupSamples
        sampleGroupSamplesCollection.sampleGroupId = sampleGroups[i].BLSAMPLEGROUPID
        sampleGroupSamplesPromise.push(this.$store.dispatch('getCollection', sampleGroupSamplesCollection))
      }
      const samplesGroupResult = await Promise.all(sampleGroupSamplesPromise)

      for (let j = 0; j < samplesGroupResult.length; j++) {
        sampleGroupSamples = sampleGroupSamples.concat(samplesGroupResult[j].toJSON())
      }

      this.sampleGroupSamples = sampleGroupSamples
    },
    updateSampleGroupInputDisabled(value) {
      this.sampleGroupInputDisabled = value
    },
    async toggleContainerQueue(queue, containerId) {
      const containerQueue = new ContainerQueue()
      const attributes = { CONTAINERID: containerId }

      if (!queue) {
        attributes.UNQUEUE = 1
      }
      return await this.$store.dispatch('saveModel', { model: containerQueue, attributes })
    }
  },
  computed: {
    containerFilter: function() {
      return [this.$store.state.proposal.proposalType]
    },
    isPuck() {
      return this.containerType.WELLPERROW === null
    },
    isPlate() {
      return this.containerType.WELLPERROW > 0
    },
    ...mapGetters({
      samples: ['samples/samples'],
    })
  },
  provide() {
    return {
      $spaceGroups: () => this.spaceGroups,
      $centringMethods: () => this.centringMethods,
      $anomalousList: () => this.anomalousList,
      $experimentKindList: () => this.experimentKindList,
      $sampleLocation: () => this.sampleLocation,
      $sampleGroups: () => this.sampleGroups,
      $queueForUDC: () => this.QUEUEFORUDC,
      $proteins: () => this.proteins,
      $sampleGroupsSamples: () => this.sampleGroupSamples,
      $sampleGroupInputDisabled: () => this.sampleGroupInputDisabled,
      $containerStatus: () => this.container ? this.container['CONTAINERSTATUS'] : null
    }
  }
}<commit_msg>remove console.log statement in code<commit_after>import Users from 'collections/users'
import ProcessingPipelines from 'collections/processingpipelines'
import SpaceGroups from 'collections/spacegroups.js'
import CentringMethodList from 'utils/centringmethods.js'
import AnomalousList from 'utils/anoms.js'
import ExperimentKindsList from 'utils/experimentkinds.js'
import DistinctProteins from 'modules/shipment/collections/distinctproteins'
import ContainerRegistry from 'modules/shipment/collections/containerregistry'
import ContainerTypes from 'modules/shipment/collections/containertypes'
import SampleGroups from 'collections/samplegroups'
import ImagingImager from 'modules/imaging/collections/imagers'
import ImagingSchedules from 'modules/imaging/collections/schedules'
import ImagingScreens from 'modules/imaging/collections/screens'
import ImagingScheduleComponents from 'modules/imaging/collections/schedulecomponents'
import { mapGetters } from 'vuex'
import Sample from 'models/sample'
import SampleGroupSamples from "collections/samplegroupsamples";
import ContainerQueue from "modules/shipment/models/containerqueue";
import { omit } from 'lodash'

const INITIAL_CONTAINER_TYPE = {
  CONTAINERTYPEID: 0,
  CAPACITY: 0,
  DROPPERWELLX: null,
  DROPPERWELLY: null,
  DROPHEIGHT: null,
  DROPWIDTH: null,
  WELLDROP: -1,
  WELLPERROW: null,
}

export default {
  data() {
    return {
      anomalousList: AnomalousList.list,

      centringMethods: CentringMethodList.list,
      containerType: {},
      containerTypes: [],
      containerTypesCollection: new ContainerTypes(),
      containerRegistryCollection: new ContainerRegistry(),
      containerRegistry: [],
      containerRegistryId: '',

      experimentTypes: [],
      experimentTypesCollection: null,
      experimentKindList: [],

      imagingImagers: [],
      imagingCollections: null,
      imagingSchedules: [],
      imagingSchedulesCollection: null,
      imagingScheduleComponents: [],
      imagingScheduleComponentsCollection: null,
      imagingScreens: [],
      imagingScreensCollections: null,

      processingPipeline: '',
      processingPipelines: [],

      proteins: [],
      proteinsCollection: new DistinctProteins(null, { state: { pageSize: 9999 }, queryParams: { per_page: 9999 } }),

      users: [],
      usersCollection: null,

      sampleGroupsCollection: null,
      sampleGroups: [],
      spaceGroups: [],
      spaceGroupsCollection: null,
      sampleGroupSamples: [],
      sampleGroupInputDisabled: false
    }
  },
  methods: {
    async getUsers() {
      this.usersCollection = new Users(null, { state: { pageSize: 9999 }})
      this.usersCollection.queryParams.all = 1
      this.usersCollection.queryParams.pid = this.$store.state.proposal.proposalModel.get('PROPOSALID')

      const result = await this.$store.dispatch('getCollection', this.usersCollection)
      this.users = result.toJSON()
      // Set plate owner to current user
      this.PERSONID = this.$store.state.user.personId
    },
    async getProcessingPipelines() {
      let processingPipelinesCollection = new ProcessingPipelines()

      processingPipelinesCollection.queryParams.pipelinestatus = 'optional'
      processingPipelinesCollection.queryParams.category = 'processing'

      const result = await this.$store.dispatch('getCollection', processingPipelinesCollection)
      this.processingPipelines = result.toJSON()
    },
    async getProteins() {
      // If we want to only allow valid samples
      if (app.options.get('valid_components') && !app.staff) {
        this.proteinsCollection.queryParams.external = 1
      }

      this.proteinsCollection.queryParams.SAFETYLEVEL = 'ALL'

      const result = await this.$store.dispatch('getCollection', this.proteinsCollection)
      this.proteins = result.toJSON()
    },
    async getContainerRegistry() {
      this.containerRegistryCollection = new ContainerRegistry(null, { state: { pageSize: 9999 }})
      const result = await this.$store.dispatch('getCollection', this.containerRegistryCollection)
      this.containerRegistry = [{ CONTAINERREGISTRYID: null, BARCODE: ""}, ...result.toJSON()]
    },
    async getContainerTypes() {
      this.containerFilter = [this.$store.state.proposal.proposalType]

      const result = await this.$store.dispatch('getCollection', this.containerTypesCollection)
      this.containerTypes = result.toJSON()
      // Do we have valid start state?
      if (this.containerTypes.length) {
        let initialContainerType = result.findWhere({PROPOSALTYPE: this.containerFilter[0]})
        this.CONTAINERTYPEID = initialContainerType ? initialContainerType.get('CONTAINERTYPEID') : ''
      }

      if (this.container) {
        let containerTypeModel = result.findWhere({NAME: this.container.CONTAINERTYPE})

        if (containerTypeModel) {
          this.containerType = Object.assign(INITIAL_CONTAINER_TYPE, containerTypeModel.toJSON())
        }
      }
    },
    formatExperimentKindList() {
      let experimentKindList = []
      for (const [key, value] of Object.entries(ExperimentKindsList.list)) {
        experimentKindList.push({ value, text: key })
      }

      this.experimentKindList = experimentKindList.filter(experimentKind => experimentKind.value)
    },
    async getSampleGroups() {
      this.sampleGroupsCollection = new SampleGroups(null, { state: { pageSize: 9999 }})

      const result = await this.$store.dispatch('getCollection', this.sampleGroupsCollection)

      this.sampleGroups = result.toJSON().map((group, index) => ({
        value: group.BLSAMPLEGROUPID,
        text: group.NAME || `Unknown Sample Group ${index}`
      }))
      this.sampleGroupInputDisabled = false
    },
    async getImagingCollections() {
      this.imagingCollections = new ImagingImager(null, { state: { pageSize: 9999 } })

      const result = await this.$store.dispatch('getCollection', this.imagingCollections)
      this.imagingImagers = result.toJSON()
    },
    async getImagingScheduleCollections() {
      this.imagingSchedulesCollection = new ImagingSchedules(null, { state: { pageSize: 9999 } })

      const result = await this.$store.dispatch('getCollection', this.imagingSchedulesCollection)
      this.imagingSchedules = result.toJSON()
    },
    async getImagingScreensCollections() {
      this.imagingScreensCollection = new ImagingScreens(null, { state: { pageSize: 9999 } })

      const result = await this.$store.dispatch('getCollection', this.imagingScreensCollection)
      this.imagingScreens = result.toJSON()
    },
    async getImagingScheduleComponentsCollection() {
      this.imagingScheduleComponentsCollection = new ImagingScheduleComponents(null, { state: { pageSize: 9999 } })
      this.imagingScheduleComponentsCollection.queryParams.shid = this.selectedSchedule.SCHEDULEID

      const result = await this.$store.dispatch('getCollection', this.imagingScheduleComponentsCollection)
      this.imagingScheduleComponents = result.toJSON()
    },
    async getSpaceGroupsCollection() {
      this.spaceGroupsCollection = new SpaceGroups(null, { state: { pageSize: 9999 } })
      if (!this.SPACEGROUP) {
        this.spaceGroupsCollection.queryParams.ty = this.containerGroup
      }

      const result = await this.$store.dispatch('getCollection', this.spaceGroupsCollection)
      this.spaceGroups = result.toJSON()
    },
    // Clone the next free row based on the current row
    onCloneSample(sampleLocation) {
      // Make sure we are using numbers for locations
      let location = +sampleLocation
      // Take the next sample in the list and copy this data
      // Locations should be in range 1..samples.length-1 (can't clone last sample in list)
      if (location < 0 || location > (this.samples.length-1)) return

      // Sample to be copied and next index
      let nextSampleIndex = -1
      // Recreate current behaviour - find the next non-zero protein id
      // This means you can click any row icon and it will fill whatever is the next empty link item based on protein id/valid acronym
      for (let i = location; i < this.samples.length; i++) {
        if (+this.samples[i]['PROTEINID'] < 0) {
          nextSampleIndex = i
          break
        }
      }

      this.cloneSample(location, nextSampleIndex)
    },
    // Clear row for a single row in the sample table
    onClearSample(sampleLocation) {
      let location = +sampleLocation
      // Clear the row for this location
      // Locations should be in range 1..samples.length
      if (location < 0 || location > this.samples.length) return
      // The location is one more than the sample index
      this.$store.commit('samples/clearSample', location)
    },
    // Take first entry (or index) and clone all rows
    onCloneContainer(sampleIndex=0) {
      for (let i = 0; i < this.samples.length; i++) {
        this.cloneSample(sampleIndex, i)
      }
    },
    // Remove all sample information from every row
    onClearContainer() {
      for (let i = 0; i < this.samples.length; i++) {
        this.$store.commit('samples/clearSample', i)
      }
    },
    // When cloning, take the last digits and pad the new samples names
    // So if 1: sample-01, 2: will equal sample-02 etc.
    generateSampleName(name, startAtIndex) {
      if (!name) return null

      let name_base = name.replace(/([\d]+)$/, '')
      let digits = name.match(/([\d]+)$/)
      let number_pad = (digits && digits.length > 1) ? digits[1].length : 0

      return name_base+((startAtIndex).toString().padStart(number_pad, '0'))
    },
    // Save the sample to the server via backbone model
    // Location should be the sample LOCATION
    async onSaveSample(location) {
      const result = await this.$refs.containerForm.validate()
      if (result) {
        await this.saveSample(location)
        const samplesRef = this.$refs.samples
        samplesRef.$refs[`sample-row-${location}`][0].closeSampleEditing()
      }
      else {
        this.$store.commit('notifications/addNotification', { message: 'Sample data is invalid, please check the form', level: 'error'})
      }
    },
    async saveSample(location) {
      let sampleIndex = +location
      // Create a new Sample Model, so it uses the BLSAMPLEID to check for post, update etc
      let sampleModel = new Sample(omit(this.samples[sampleIndex], 'STRATEGYOPTION'))

      const result = await this.$store.dispatch('saveModel', { model: sampleModel })

      if (!this.samples[sampleIndex]['BLSAMPLEID'])
        this.$store.commit('samples/updateSamplesField', {
          path: `samples/${sampleIndex}/BLSAMPLEID`,
          value: result.get('BLSAMPLEID')
        })
    },
    getRowColDrop(pos) {
      let well = this.containerType.WELLDROP > -1 ? 1 : 0
      let dropTotal = (this.containerType.DROPPERWELLX * this.containerType.DROPPERWELLY) - well

      const wellPosition = Math.floor((parseInt(pos) - 1) / dropTotal);
      const drop = ((pos - 1) % dropTotal) + 1;

      const col = wellPosition % this.containerType.WELLPERROW;
      const row = Math.floor(wellPosition / this.containerType.WELLPERROW);

      return { row: row, col: col, drop: drop, pos: pos }
    },
    // While updating the sample locations during the cloning, the update will stop is one of the form field is invalid.
    async onCloneColumn(location) {
      let sampleIndex = +location - 1
      let sourceCoordinates = this.getRowColDrop(location)

      for (let i = 0; i < this.samples.length; i++) {
        // We are only cloning samples that come after this one - so skip any with a lower index
        if (i > sampleIndex) {
          let targetCoordinates = this.getRowColDrop(this.samples[i].LOCATION)

          if (targetCoordinates['drop'] === sourceCoordinates['drop'] && targetCoordinates['col'] === sourceCoordinates['col']) {
            this.cloneSample(sampleIndex, i)
            this.sampleLocation = i

            await this.$nextTick()
            const locationValid = await this.$refs.containerForm.validate();

            if (!locationValid) {
              break
            } else {
              this.$store.commit('samples/updateSamplesField', {
                path: `samples/${sampleIndex}/VALID`,
                value: 1
              })
            }
          }
        }
      }
    },
    // While updating the sample locations during the cloning, the update will stop is one of the form field is invalid.
    async onCloneRow(location) {
      let sampleIndex = +location - 1
      let sourceCoordinates = this.getRowColDrop(location)

      for (let i = 0; i < this.samples.length; i++) {
        // We are only cloning samples that come after this one - so skip any with a lower index
        if (i > sampleIndex) {
          let targetCoordinates = this.getRowColDrop(this.samples[i].LOCATION)

          if (targetCoordinates['drop'] === sourceCoordinates['drop'] && targetCoordinates['row'] === sourceCoordinates['row']) {
            this.cloneSample(sampleIndex, i)
            this.sampleLocation = i

            await this.$nextTick()
            const locationValid = await this.$refs.containerForm.validate();

            if (!locationValid) {
              break
            } else {
              this.$store.commit('samples/updateSamplesField', {
                path: `samples/${sampleIndex}/VALID`,
                value: 1
              })
            }
          }
        }
      }
    },
    cloneSample(sourceIndex, targetIndex) {
      if (targetIndex < 0 || targetIndex >= this.samples.length) return false
      if (sourceIndex < 0 || sourceIndex >= this.samples.length) return false

      let sourceSample = this.samples[sourceIndex]
      if (sourceSample.PROTEINID < 0) return false

      let baseName = this.samples[sourceIndex].NAME
      let sampleClone = { ...this.samples[targetIndex], ...this.samples[sourceIndex] }
      sampleClone.LOCATION = (targetIndex + 1).toString()
      sampleClone.NAME = this.generateSampleName(baseName, targetIndex+1)
      this.$store.commit('samples/setSample', { index: targetIndex, data: sampleClone })
    },
    // Reset the validation for the field when an input is edited
    resetFormValidation() {
      requestAnimationFrame(() => {
        this.$refs.containerForm.reset()
      })
    },
    async fetchSampleGroupSamples() {
      const sampleGroupCollection = new SampleGroups(null, { state: { pageSize: 9999 } })

      const result = await this.$store.dispatch('getCollection', sampleGroupCollection)
      const sampleGroups = result.toJSON()

      let sampleGroupSamples = []
      let sampleGroupSamplesPromise = []

      for (let i = 0; i < sampleGroups.length; i++) {
        const sampleGroupSamplesCollection = new SampleGroupSamples
        sampleGroupSamplesCollection.sampleGroupId = sampleGroups[i].BLSAMPLEGROUPID
        sampleGroupSamplesPromise.push(this.$store.dispatch('getCollection', sampleGroupSamplesCollection))
      }
      const samplesGroupResult = await Promise.all(sampleGroupSamplesPromise)

      for (let j = 0; j < samplesGroupResult.length; j++) {
        sampleGroupSamples = sampleGroupSamples.concat(samplesGroupResult[j].toJSON())
      }

      this.sampleGroupSamples = sampleGroupSamples
    },
    updateSampleGroupInputDisabled(value) {
      this.sampleGroupInputDisabled = value
    },
    async toggleContainerQueue(queue, containerId) {
      const containerQueue = new ContainerQueue()
      const attributes = { CONTAINERID: containerId }

      if (!queue) {
        attributes.UNQUEUE = 1
      }
      return await this.$store.dispatch('saveModel', { model: containerQueue, attributes })
    }
  },
  computed: {
    containerFilter: function() {
      return [this.$store.state.proposal.proposalType]
    },
    isPuck() {
      return this.containerType.WELLPERROW === null
    },
    isPlate() {
      return this.containerType.WELLPERROW > 0
    },
    ...mapGetters({
      samples: ['samples/samples'],
    })
  },
  provide() {
    return {
      $spaceGroups: () => this.spaceGroups,
      $centringMethods: () => this.centringMethods,
      $anomalousList: () => this.anomalousList,
      $experimentKindList: () => this.experimentKindList,
      $sampleLocation: () => this.sampleLocation,
      $sampleGroups: () => this.sampleGroups,
      $queueForUDC: () => this.QUEUEFORUDC,
      $proteins: () => this.proteins,
      $sampleGroupsSamples: () => this.sampleGroupSamples,
      $sampleGroupInputDisabled: () => this.sampleGroupInputDisabled,
      $containerStatus: () => this.container ? this.container['CONTAINERSTATUS'] : null
    }
  }
}<|endoftext|>


<commit_before>/*
---

script: DOM.js

description: Provides DOM-compliant interface to play around with other widgets

license: Public domain (http://unlicense.org).

authors: Yaroslaff Fedin

requires:
  - LSD.Module
  - LSD.Module.Events

provides:
  - LSD.Module.DOM
  - LSD.Module.DOM.findDocument

...
*/

!function() {

LSD.Module.DOM = new Class({
  constructors: {
    dom: function(options) {
      this.nodeType = options.nodeType || 1;
      this.childNodes = [];
    }
  },

  contains: function(element) {
    while (element = element.parentNode) if (element == this) return true;
    return false;
  },

  getChildren: function() {
    return this.childNodes;
  },

  setParent: function(widget, index){
    if (!widget.lsd) widget = LSD.Module.DOM.find(widget);
    if (!widget) return;
    var old = this.properties.parent;
    var changed = this.properties.set('parent', widget);
    if (changed) {
      if (old) old.removeChild(this);
    } else {
      var previous = this.childNodes.indexOf(widget);
      if (previous != index - 1) unset.call(this, widget);
      this.childNodes.splice(previous, 1);
      if (previous != index - 1) return;
    }
    set.call(this, widget, index);
    var previous = this.previousSibling;
    var start = previous ? (previous.sourceLastIndex || previous.sourceIndex) : widget.sourceIndex || (widget.sourceIndex = 1);
    var sourceIndex = start;
    LSD.Module.DOM.each(this, function(node) {
      node.sourceIndex = ++ sourceIndex;
      if (node.sourceLastIndex) node.sourceLastIndex += start;
      for (var parent = widget; parent; parent = parent.parentNode) {
        parent.sourceLastIndex = (parent.sourceLastIndex || parent.sourceIndex) ;
        if (!changed) continue;
        var events = parent.$events.nodeInserted;
        if (!events) continue;
        for (var i = 0, j = events.length, fn; i < j; i++)
          if ((fn = events[i])) fn.call(parent, node);
      }
    }, this);
  },

  unsetParent: function(widget, index) {
    if (!widget) widget = this.parentNode;
    LSD.Module.DOM.each(this, function(node) {
      widget.dispatchEvent('nodeRemoved', node);
    });
    this.removed = true;
    unset.call(this, widget, index);
    this.properties.unset('parent', widget);
    delete this.removed;
  },

  appendChild: function(child, element) {
    if (child.lsd) {
      child.parentNode = this;
      var result = this.captureEvent('appendChild', arguments);
      if (result === false) return false;
    }
    if (element !== false) {
      if (element == null) element = this.element || this.toElement();
      if (child.lsd && child.getParentElement) element = child.getParentElement(element, this);
      var node = child.lsd ? (child.element || child.toElement()) : child;
      if (node.parentNode != element) element.appendChild(node);
    }
    if (child.lsd) {
      // set parent 'for real' and do callbacks
      child.setParent(this, this.childNodes.push(child) - 1);
      if (this.document && child.properties.document != this.document)
        child.properties.set('document', this.document);
      if (this.document.rendered && !child.rendered) child.render()
    }
    return true;
  },

  removeChild: function(child, element) {
    var widget = LSD.Module.DOM.find(child, true);
    if (widget) {
      child = widget.element;
      var index = this.childNodes.indexOf(widget);
      if (index > -1) {
        widget.unsetParent(this, index);
        this.childNodes.splice(index, 1);
      }
    }
    if (child && child.parentNode) child.parentNode.removeChild(child)
  },

  replaceChild: function(insertion, child) {
    var index = this.childNodes.indexOf(child);
    if (index == -1) return;
    this.removeChild(child);
    this.childNodes.splice(index, 0, insertion);
    insertion.setParent(this, index);
  },

  insertBefore: function(insertion, node) {
    var widget = LSD.Module.DOM.findNext(node);
    var index = widget && widget != this ? this.childNodes.indexOf(widget) : this.childNodes.length;
    if (index == -1) return;
    this.childNodes.splice(index, 0, insertion);
    if (!node) {
      if (index) insertion.toElement().inject(this.childNodes[index - 1].toElement(), 'after')
      else this.toElement().appendChild(insertion.toElement())
    } else this.toElement().insertBefore(insertion.toElement(), node.element || node);
    insertion.setParent(this, index);
    return this;
  },

  cloneNode: function(children, options) {
    var clone = this.factory.create(this.element.cloneNode(children), Object.merge({
      source: this.source,
      tag: this.tagName,
      pseudos: this.pseudos.toObject(),
      traverse: !!children
    }, options));
    return clone;
  },

  inject: function(node, where) {
    if (!node.lsd) {
      var instance = LSD.Module.DOM.find(node, true);
      if (instance) widget = instance;
    } else var widget = node;
    if (where === false) {
      if (widget) widget.appendChild(this, false);
    } else if (!inserters[where || 'bottom'](widget ? this : this.toElement(), widget || node)) return false;
    if (widget && widget.rendered) widget.render();
    return this;
  },

  grab: function(node, where){
    if (!node.lsd) {
      var instance = LSD.Module.DOM.find(widget, true);
      if (instance) widget = instance;
    } else var widget = node;
    if (where === false) {
      if (widget) this.appendChild(widget, false);
    } else if (!inserters[where || 'bottom'](widget || node, widget ? this : this.toElement())) return false;
    return this;
  },

  /*
    Wrapper is where content nodes get appended.
    Defaults to this.element, but can be redefined
    in other Modules or Traits (as seen in Container
    module)
  */

  getWrapper: function() {
    return this.toElement();
  },

  write: function(content, hard) {
    if (!content || !(content = content.toString())) return;
    var wrapper = this.getWrapper();
    if (hard && this.written) for (var node; node = this.written.shift();) Element.dispose(node);
    var fragment = document.createFragment(content);
    var written = LSD.slice(fragment.childNodes);
    if (!hard && this.written) this.written.push.apply(this.written, written);
    else this.written = written;
    wrapper.appendChild(fragment);
    this.fireEvent('write', [written, hard])
    this.innerText = wrapper.get('text').trim();
    return written;
  },

  replaces: function(el){
    this.inject(el, 'after');
    el.dispose();
    return this;
  },

  dispose: function() {
    var parent = this.parentNode;
    if (!parent) return;
    this.fireEvent('beforeDispose', parent);
    parent.removeChild(this);
    this.fireEvent('dispose', parent);
    return this;
  }
});

var set = function(widget, index) {
  var siblings = widget.childNodes, length = siblings.length;
  if (siblings[0] == this) widget.properties.write('first', this);
  if (siblings[siblings.length - 1] == this) widget.properties.write('last', this);
  if (index == null) index = length - 1;
  var previous = siblings[index - 1], next = siblings[index + 1];
  if (previous) {
    if (previous == this) throw "Previous sibling link points to the same node inevitably causing infinite loop";
    previous.properties.write('next', this);
    this.properties.write('previous', previous);
  }
  if (next) {
    if (next == this) throw "Previous sibling link points to the same node inevitably causing infinite loop";
    next.properties.write('previous', this);
    this.properties.write('next', next);
  }
  return index;
};

var unset = function(widget, index) {
  var parent = this.parentNode, siblings = widget.childNodes;
  if (index == null) index = siblings.indexOf(this);
  var previous = siblings[index - 1], next = siblings[index + 1];
  if (previous) {
    previous.properties.write('next', next);
    this.properties.unset('previous', previous);
  }
  if (next) {
    if (previous) this.properties.write('next', previous);
    next.properties.unset('previous', this);
  }
  if (parent.firstChild == this) {
    if (next) parent.properties.write('first', next);
    else parent.properties.unset('first', this);
  }
  if (parent.lastChild == this) {
    if (previous) parent.properties.write('last', previous);
    else parent.properties.unset('last', this);
  }
  return index;
};

/*
  `inject` and `grab` methods accept optional argument that defines
  the position where the element should be placed.

  These are the unedited duplicate of mootools element inserters.
  All of the manipilations boil down to either `insertBefore` or
  `appendChild`.
*/

var inserters = {
  before: function(context, element){
    var parent = element.parentNode;
    if (parent) return parent.insertBefore(context, element);
  },

  after: function(context, element){
    var parent = element.parentNode;
    if (parent) return parent.insertBefore(context, element.nextSibling);
  },

  bottom: function(context, element){
    return element.appendChild(context);
  },

  top: function(context, element){
    return element.insertBefore(context, element.firstChild);
  }
};

Object.append(LSD.Module.DOM, {
  dispose: function(node) {

  },

  destroy: function(node) {
    var child = LSD.Module.DOM.identify(node);
    LSD.Module.DOM.walk(child.element, function(element) {
      var widget = element.uid && LSD.Module.DOM.find(element, true);
      if (widget) widget.destroy(true);
    });
    Element.destroy(child.element);
  },

  clone: function(node, parent, before) {
    var child = LSD.Module.DOM.identify(node);
    parent = (parent === true || parent == null) ? [child.parent, child.element.parentNode] : parent || false;
    before = before === true ? child.element : before || child.element.nextSibling;
    return child.parent.document.layout.render(child.element, parent, {clone: true, before: before});
  },

  walk: function(node, callback, bind, memo) {
    if (node.lsd) node = node.element || node.toElement();
    var result = callback.call(bind || this, node, memo);
    if (result !== false)
      for (var children = node.childNodes, child, i = 0; child = children[i]; i++)
        if (child.nodeType == 1) LSD.Module.DOM.walk(child, callback, bind, memo);
    return memo;
  },

  each: function(node, callback, bind, memo) {
    var widget = node.lsd ? node : LSD.Module.DOM.find(node, true);
    if (widget) {
      var result = callback.call(bind || this, widget, memo);
      if (result === false) return memo;
      if (result) (memo || (memo = [])).push(widget);
    }
    for (var children = node.childNodes, child, i = 0; child = children[i]; i++)
      if (child.nodeType == 1) LSD.Module.DOM.each(child, callback, bind, memo);
    return memo;
  },

  find: function(node, lazy) {
    return node.lsd ? node : ((!lazy || node.uid) && Element[lazy ? 'retrieve' : 'get'](node, 'widget'));
  },

  identify: function(node) {
    var widget = LSD.Module.DOM.find(node);
    if ((node.lsd ? widget : widget && widget.element) == node)
      return {element: widget.element, widget: widget, parent: widget.parentNode};
    else
      return {element: node, parent: widget};
  },

  getID: function(node) {
    if (node.lsd) {
      return node.attributes.itemid;
    } else {
      return node.getAttribute('itemid');
    }
  },

  findNext: function(node) {
    var widget = node;
    if (widget && !widget.lsd)
      if (!node.uid || !(widget = node.retrieve('widget')))
        for (var item = node, stack = [item.nextSibling]; item = stack.pop();)
          if (item.uid && (widget = item.retrieve('widget'))) {
            break;
          } else {
            if ((widget = item.nextSibling)) stack.push(widget);
            else stack.push(item.parentNode);
          }
    return widget;
  }
});

}();

LSD.Options.document = {
  add: function(document) {
    this.properties.set('document', document)
  },
  remove: function(document) {
    this.properties.unset('document', document)
  }
};<commit_msg>Finalize the setParent 'same parent' detection<commit_after>/*
---

script: DOM.js

description: Provides DOM-compliant interface to play around with other widgets

license: Public domain (http://unlicense.org).

authors: Yaroslaff Fedin

requires:
  - LSD.Module
  - LSD.Module.Events

provides:
  - LSD.Module.DOM
  - LSD.Module.DOM.findDocument

...
*/

!function() {

LSD.Module.DOM = new Class({
  constructors: {
    dom: function(options) {
      this.nodeType = options.nodeType || 1;
      this.childNodes = [];
    }
  },

  contains: function(element) {
    while (element = element.parentNode) if (element == this) return true;
    return false;
  },

  getChildren: function() {
    return this.childNodes;
  },

  setParent: function(widget, index){
    if (!widget.lsd) widget = LSD.Module.DOM.find(widget);
    if (!widget) return;
    var old = this.properties.parent;
    var length = widget.childNodes.length;
    if (old)
      if (old != widget) {
        old.removeChild(this);
      } else {
        var previous = widget.childNodes.indexOf(this);
        if (previous != index) {
          var same = index == length - 1 && previous == index - 1;
          if (!same) unset.call(this, widget);
          widget.childNodes.splice(previous, 1);
          if (same) return;
        } else return
      }
    this.properties.set('parent', widget);
    set.call(this, widget, index);
    var previous = this.previousSibling;
    var start = previous ? (previous.sourceLastIndex || previous.sourceIndex) : widget.sourceIndex || (widget.sourceIndex = 1);
    var sourceIndex = start;
    LSD.Module.DOM.each(this, function(node) {
      node.sourceIndex = ++ sourceIndex;
      if (node.sourceLastIndex) node.sourceLastIndex += start;
      for (var parent = widget; parent; parent = parent.parentNode) {
        parent.sourceLastIndex = (parent.sourceLastIndex || parent.sourceIndex) ;
        if (old == widget) continue;
        var events = parent.$events.nodeInserted;
        if (!events) continue;
        for (var i = 0, j = events.length, fn; i < j; i++)
          if ((fn = events[i])) fn.call(parent, node);
      }
    }, this);
  },

  unsetParent: function(widget, index) {
    if (!widget) widget = this.parentNode;
    LSD.Module.DOM.each(this, function(node) {
      widget.dispatchEvent('nodeRemoved', node);
    });
    this.removed = true;
    unset.call(this, widget, index);
    this.properties.unset('parent', widget);
    delete this.removed;
  },

  appendChild: function(child, element) {
    if (child.lsd) {
      child.parentNode = this;
      var result = this.captureEvent('appendChild', arguments);
      if (result === false) return false;
    }
    if (element !== false) {
      if (element == null) element = this.element || this.toElement();
      if (child.lsd && child.getParentElement) element = child.getParentElement(element, this);
      var node = child.lsd ? (child.element || child.toElement()) : child;
      if (node.parentNode != element) element.appendChild(node);
    }
    if (child.lsd) {
      // set parent 'for real' and do callbacks
      child.setParent(this, this.childNodes.push(child) - 1);
      if (this.document && child.properties.document != this.document)
        child.properties.set('document', this.document);
      if (this.document.rendered && !child.rendered) child.render()
    }
    return true;
  },

  removeChild: function(child, element) {
    var widget = LSD.Module.DOM.find(child, true);
    if (widget) {
      child = widget.element;
      var index = this.childNodes.indexOf(widget);
      if (index > -1) {
        widget.unsetParent(this, index);
        this.childNodes.splice(index, 1);
      }
    }
    if (child && child.parentNode) child.parentNode.removeChild(child)
  },

  replaceChild: function(insertion, child) {
    var index = this.childNodes.indexOf(child);
    if (index == -1) return;
    this.removeChild(child);
    this.childNodes.splice(index, 0, insertion);
    insertion.setParent(this, index);
  },

  insertBefore: function(insertion, node) {
    var widget = LSD.Module.DOM.findNext(node);
    var index = widget && widget != this ? this.childNodes.indexOf(widget) : this.childNodes.length;
    if (index == -1) return;
    this.childNodes.splice(index, 0, insertion);
    if (!node) {
      if (index) insertion.toElement().inject(this.childNodes[index - 1].toElement(), 'after')
      else this.toElement().appendChild(insertion.toElement())
    } else this.toElement().insertBefore(insertion.toElement(), node.element || node);
    insertion.setParent(this, index);
    return this;
  },

  cloneNode: function(children, options) {
    var clone = this.factory.create(this.element.cloneNode(children), Object.merge({
      source: this.source,
      tag: this.tagName,
      pseudos: this.pseudos.toObject(),
      traverse: !!children
    }, options));
    return clone;
  },

  inject: function(node, where) {
    if (!node.lsd) {
      var instance = LSD.Module.DOM.find(node, true);
      if (instance) widget = instance;
    } else var widget = node;
    if (where === false) {
      if (widget) widget.appendChild(this, false);
    } else if (!inserters[where || 'bottom'](widget ? this : this.toElement(), widget || node)) return false;
    if (widget && widget.rendered) widget.render();
    return this;
  },

  grab: function(node, where){
    if (!node.lsd) {
      var instance = LSD.Module.DOM.find(widget, true);
      if (instance) widget = instance;
    } else var widget = node;
    if (where === false) {
      if (widget) this.appendChild(widget, false);
    } else if (!inserters[where || 'bottom'](widget || node, widget ? this : this.toElement())) return false;
    return this;
  },

  /*
    Wrapper is where content nodes get appended.
    Defaults to this.element, but can be redefined
    in other Modules or Traits (as seen in Container
    module)
  */

  getWrapper: function() {
    return this.toElement();
  },

  write: function(content, hard) {
    if (!content || !(content = content.toString())) return;
    var wrapper = this.getWrapper();
    if (hard && this.written) for (var node; node = this.written.shift();) Element.dispose(node);
    var fragment = document.createFragment(content);
    var written = LSD.slice(fragment.childNodes);
    if (!hard && this.written) this.written.push.apply(this.written, written);
    else this.written = written;
    wrapper.appendChild(fragment);
    this.fireEvent('write', [written, hard])
    this.innerText = wrapper.get('text').trim();
    return written;
  },

  replaces: function(el){
    this.inject(el, 'after');
    el.dispose();
    return this;
  },

  dispose: function() {
    var parent = this.parentNode;
    if (!parent) return;
    this.fireEvent('beforeDispose', parent);
    parent.removeChild(this);
    this.fireEvent('dispose', parent);
    return this;
  }
});

var set = function(widget, index) {
  var siblings = widget.childNodes, length = siblings.length;
  if (siblings[0] == this) widget.properties.write('first', this);
  if (siblings[siblings.length - 1] == this) widget.properties.write('last', this);
  if (index == null) index = length - 1;
  var previous = siblings[index - 1], next = siblings[index + 1];
  if (previous) {
    if (previous == this) throw "Previous sibling link points to the same node inevitably causing infinite loop";
    previous.properties.write('next', this);
    this.properties.write('previous', previous);
  }
  if (next) {
    if (next == this) throw "Previous sibling link points to the same node inevitably causing infinite loop";
    next.properties.write('previous', this);
    this.properties.write('next', next);
  }
  return index;
};

var unset = function(widget, index) {
  var parent = this.parentNode, siblings = widget.childNodes;
  if (index == null) index = siblings.indexOf(this);
  var previous = siblings[index - 1], next = siblings[index + 1];
  if (previous) {
    previous.properties.write('next', next);
    this.properties.unset('previous', previous);
  }
  if (next) {
    if (previous) this.properties.write('next', previous);
    next.properties.unset('previous', this);
  }
  if (parent.firstChild == this) {
    if (next) parent.properties.write('first', next);
    else parent.properties.unset('first', this);
  }
  if (parent.lastChild == this) {
    if (previous) parent.properties.write('last', previous);
    else parent.properties.unset('last', this);
  }
  return index;
};

/*
  `inject` and `grab` methods accept optional argument that defines
  the position where the element should be placed.

  These are the unedited duplicate of mootools element inserters.
  All of the manipilations boil down to either `insertBefore` or
  `appendChild`.
*/

var inserters = {
  before: function(context, element){
    var parent = element.parentNode;
    if (parent) return parent.insertBefore(context, element);
  },

  after: function(context, element){
    var parent = element.parentNode;
    if (parent) return parent.insertBefore(context, element.nextSibling);
  },

  bottom: function(context, element){
    return element.appendChild(context);
  },

  top: function(context, element){
    return element.insertBefore(context, element.firstChild);
  }
};

Object.append(LSD.Module.DOM, {
  dispose: function(node) {

  },

  destroy: function(node) {
    var child = LSD.Module.DOM.identify(node);
    LSD.Module.DOM.walk(child.element, function(element) {
      var widget = element.uid && LSD.Module.DOM.find(element, true);
      if (widget) widget.destroy(true);
    });
    Element.destroy(child.element);
  },

  clone: function(node, parent, before) {
    var child = LSD.Module.DOM.identify(node);
    parent = (parent === true || parent == null) ? [child.parent, child.element.parentNode] : parent || false;
    before = before === true ? child.element : before || child.element.nextSibling;
    return child.parent.document.layout.render(child.element, parent, {clone: true, before: before});
  },

  walk: function(node, callback, bind, memo) {
    if (node.lsd) node = node.element || node.toElement();
    var result = callback.call(bind || this, node, memo);
    if (result !== false)
      for (var children = node.childNodes, child, i = 0; child = children[i]; i++)
        if (child.nodeType == 1) LSD.Module.DOM.walk(child, callback, bind, memo);
    return memo;
  },

  each: function(node, callback, bind, memo) {
    var widget = node.lsd ? node : LSD.Module.DOM.find(node, true);
    if (widget) {
      var result = callback.call(bind || this, widget, memo);
      if (result === false) return memo;
      if (result) (memo || (memo = [])).push(widget);
    }
    for (var children = node.childNodes, child, i = 0; child = children[i]; i++)
      if (child.nodeType == 1) LSD.Module.DOM.each(child, callback, bind, memo);
    return memo;
  },

  find: function(node, lazy) {
    return node.lsd ? node : ((!lazy || node.uid) && Element[lazy ? 'retrieve' : 'get'](node, 'widget'));
  },

  identify: function(node) {
    var widget = LSD.Module.DOM.find(node);
    if ((node.lsd ? widget : widget && widget.element) == node)
      return {element: widget.element, widget: widget, parent: widget.parentNode};
    else
      return {element: node, parent: widget};
  },

  getID: function(node) {
    if (node.lsd) {
      return node.attributes.itemid;
    } else {
      return node.getAttribute('itemid');
    }
  },

  findNext: function(node) {
    var widget = node;
    if (widget && !widget.lsd)
      if (!node.uid || !(widget = node.retrieve('widget')))
        for (var item = node, stack = [item.nextSibling]; item = stack.pop();)
          if (item.uid && (widget = item.retrieve('widget'))) {
            break;
          } else {
            if ((widget = item.nextSibling)) stack.push(widget);
            else stack.push(item.parentNode);
          }
    return widget;
  }
});

}();

LSD.Options.document = {
  add: function(document) {
    this.properties.set('document', document)
  },
  remove: function(document) {
    this.properties.unset('document', document)
  }
};<|endoftext|>


<commit_before>QUnit.module( "QUnit.objectType" );

function Foo( ) { }

function validateObjectType( item, expected ) {
	QUnit.test( "should properly detect " + expected, function( assert ) {
		assert.expect( 1 );

		var actual = QUnit.objectType( item );
		assert.equal( actual, expected );
	} );
}

function maybeValidateObjectType( string, expected ) {
	try {
		var value = new Function( "return " + string + ";" )( );
		validateObjectType( value, expected );
	} catch ( e ) {

		// do nothing if parsing failed
		if ( e.name === "SyntaxError" ) {
			return;
		}

		// do not hide other errors
		throw e;
	}
}

validateObjectType( 1, "number" );
validateObjectType( "", "string" );
validateObjectType( "foo", "string" );
validateObjectType( null, "null" );
validateObjectType( true, "boolean" );
validateObjectType( false, "boolean" );
validateObjectType( [ ], "array" );
validateObjectType( new Date( ), "date" );
validateObjectType( /foo/, "regexp" );
validateObjectType( NaN, "nan" );
validateObjectType( undefined, "undefined" );
validateObjectType( { }, "object" );
validateObjectType( new Foo( ), "object" );

if ( typeof Symbol === "function" ) {
	validateObjectType( Symbol( "HI!" ), "symbol" );
}

if ( typeof Map === "function" ) {
	validateObjectType( new Map( ), "map" );
}

if ( typeof Set === "function" ) {
	validateObjectType( new Set( ), "set" );
}

maybeValidateObjectType( "async function() { }", "function" );
maybeValidateObjectType( "async () => { }", "function" );
maybeValidateObjectType( "() => { }", "function" );
maybeValidateObjectType( "function* { }", "function" );
<commit_msg>Tests: Skip Map and Set cases for QUnit.objectType() on IE 11<commit_after>QUnit.module( "QUnit.objectType" );

function Foo( ) { }

function validateObjectType( item, expected ) {
	QUnit.test( "should properly detect " + expected, function( assert ) {
		assert.expect( 1 );

		var actual = QUnit.objectType( item );
		assert.equal( actual, expected );
	} );
}

function maybeValidateObjectType( string, expected ) {
	try {
		var value = new Function( "return " + string + ";" )( );
		validateObjectType( value, expected );
	} catch ( e ) {

		// do nothing if parsing failed
		if ( e.name === "SyntaxError" ) {
			return;
		}

		// do not hide other errors
		throw e;
	}
}

validateObjectType( 1, "number" );
validateObjectType( "", "string" );
validateObjectType( "foo", "string" );
validateObjectType( null, "null" );
validateObjectType( true, "boolean" );
validateObjectType( false, "boolean" );
validateObjectType( [ ], "array" );
validateObjectType( new Date( ), "date" );
validateObjectType( /foo/, "regexp" );
validateObjectType( NaN, "nan" );
validateObjectType( undefined, "undefined" );
validateObjectType( { }, "object" );
validateObjectType( new Foo( ), "object" );

if ( typeof Symbol === "function" ) {
	validateObjectType( Symbol( "HI!" ), "symbol" );
}

// Support IE 11: Skip on IE11's non-compliant implementation
if ( typeof Map === "function" && ( new Map ).toString() !== "[object Object]" ) {
	validateObjectType( new Map( ), "map" );
}

// Support IE 11: Skip on IE11's non-compliant implementation
if ( typeof Set === "function" && ( new Set ).toString() !== "[object Object]" ) {
	validateObjectType( new Set( ), "set" );
}

maybeValidateObjectType( "async function() { }", "function" );
maybeValidateObjectType( "async () => { }", "function" );
maybeValidateObjectType( "() => { }", "function" );
maybeValidateObjectType( "function* { }", "function" );
<|endoftext|>


<commit_before>'use strict';

var should = require('should');
var async = require('async');
var rarity = require('rarity');

var AnyFetch = require('../../lib/index.js');
require('../helpers/reset-to-bearer.js');
var configuration = require('../../config/configuration.js');

describe('<Low-level mapping functions>', function() {
  var anyfetch;
  before(function instantiateClient() {
    anyfetch = new AnyFetch(configuration.test.user.email, configuration.test.user.password);
  });

  describe('Basic authentication', function() {
    it('should retrieve token from credentials', function(done) {
      var anyfetch = new AnyFetch(configuration.test.user.email, configuration.test.user.password);
      anyfetch.getToken(function(err, res) {
        should(res).be.ok;
        should(res.body).be.ok;
        res.body.should.have.keys(['token']);
        done(err);
      });
    });
  });

  describe('getBatch', function() {
    var expected = configuration.apiDescriptors.getBatch;
    var res;
    var pages = [
      '/document_types',
      '/providers'
    ];

    it('should carry out the request', function(done) {
      anyfetch.getBatch({ pages: pages }, function(e, r) {
        res = r;
        done(e);
      });
    });

    it('should use the correct verb', function() {
      res.req.method.should.equal(expected.verb);
    });

    it('should target the correct endpoint', function() {
      res.req.path.should.startWith(expected.endpoint);
    });

    it('should have the expected return code', function() {
      res.res.statusCode.should.equal(expected.expectedStatus);
    });

    it('should respond with an object with one key per page', function() {
      res.body.should.have.keys(pages);
    });
  });

  describe('getProviderById', function() {
    it('should retrieve a single provider by its id', function(done) {
      // We use a dummy error to bail out of waterfall
      // Otherwise, it might cause a leak
      var noProvider = new Error('No provider available');

      async.waterfall([
        function getAlProviders(cb) {
          anyfetch.getProviders(cb);
        },
        function extractFirstId(res, cb) {
          var providerIds = Object.keys(res.body);
          if(!providerIds || providerIds.length < 1) {
            return cb(noProvider);
          }
          cb(null, providerIds[0]);
        },
        function getSingleProvider(id, cb) {
          anyfetch.getProviderById(id, rarity.carry(id, cb));
        },
        function checkProvider(id, res, cb) {
          var provider = res.body;
          provider.should.have.properties({ 'id': id });
          cb(null);
        }
      ], function(err) {
        // Do not fail if there's zero provider to test on
        if(err === noProvider) {
          return done();
        }
        done(err);
      });
    });
  });
});
<commit_msg>Fix `getProviderById` test<commit_after>'use strict';

var should = require('should');
var async = require('async');
var rarity = require('rarity');

var AnyFetch = require('../../lib/index.js');
require('../helpers/reset-to-bearer.js');
var configuration = require('../../config/configuration.js');

describe('<Low-level mapping functions>', function() {
  var anyfetch;
  before(function instantiateClient() {
    anyfetch = new AnyFetch(configuration.test.user.email, configuration.test.user.password);
  });

  describe('Basic authentication', function() {
    it('should retrieve token from credentials', function(done) {
      var anyfetch = new AnyFetch(configuration.test.user.email, configuration.test.user.password);
      anyfetch.getToken(function(err, res) {
        should(res).be.ok;
        should(res.body).be.ok;
        res.body.should.have.keys(['token']);
        done(err);
      });
    });
  });

  describe('getBatch', function() {
    var expected = configuration.apiDescriptors.getBatch;
    var res;
    var pages = [
      '/document_types',
      '/providers'
    ];

    it('should carry out the request', function(done) {
      anyfetch.getBatch({ pages: pages }, function(e, r) {
        res = r;
        done(e);
      });
    });

    it('should use the correct verb', function() {
      res.req.method.should.equal(expected.verb);
    });

    it('should target the correct endpoint', function() {
      res.req.path.should.startWith(expected.endpoint);
    });

    it('should have the expected return code', function() {
      res.res.statusCode.should.equal(expected.expectedStatus);
    });

    it('should respond with an object with one key per page', function() {
      res.body.should.have.keys(pages);
    });
  });

  describe('getProviderById', function() {
    it('should retrieve a single provider by its id', function(done) {
      // We use a dummy error to bail out of waterfall
      // Otherwise, it might cause a leak
      var noProvider = new Error('No provider available');

      async.waterfall([
        function getAlProviders(cb) {
          anyfetch.getProviders(cb);
        },
        function extractFirstId(res, cb) {
          var providers = res.body;
          if(!providers || providers.length < 1) {
            return cb(noProvider);
          }
          cb(null, providers[0].id);
        },
        function getSingleProvider(id, cb) {
          anyfetch.getProviderById(id, rarity.carry(id, cb));
        },
        function checkProvider(id, res, cb) {
          var provider = res.body;
          provider.should.have.properties({ 'id': id });
          cb(null);
        }
      ], function(err) {
        // Do not fail if there's zero provider to test on
        if(err === noProvider) {
          return done();
        }
        done(err);
      });
    });
  });
});
<|endoftext|>


<commit_before>/** MIT License (c) copyright B Cavalier & J Hann */

/**
 * curl dojo 1.6 shim
 *
 * Licensed under the MIT License at:
 * 		http://www.opensource.org/licenses/mit-license.php
 */

/**
 * Until AMD becomes well established, there will be issues with the various
 * libs.  This one overcomes some minor issues with dojo 1.6's initial
 * foray into AMD territory. :)
 *
 * usage:
 *  curl(['curl/shim/dojo16', 'curl/domReady'])
 *  	.next(['dojo/parser'])
 *  	.then(function (parser) {
 *  		parser.parse();
 *  	});
 *
 */
var require;
define(/*=='curl/shim/dojo16',==*/ ['curl/_privileged', 'curl/domReady'], function (priv, domReady) {
"use strict";

	var _curl = priv['_curl'],
		origExecuteDefFunc = priv['core'].executeDefFunc;

	function duckPunchRequire (req) {
		// create a ready method on `require`
		if (!req['ready']){
			req['ready'] = function (cb) {
				domReady(cb);
			};
		}
		// map non-standard nameToUrl to toUrl
		if (!req['nameToUrl']) {
			req['nameToUrl'] = function (name, ext) {
				return req['toUrl'](name + (ext || ''));
			};
		}
		// dojo 1.7 has a few unchecked `require.cache` usages
		if (!req['cache']) req['cache'] = {};
		return req;
	}

	// modify global curl cuz dojo doesn't always use local `require`
	// as a dependency
	duckPunchRequire(_curl);

	// dojo 1.7 still expects a global `require`, so make sure they've got one
	if (typeof require == 'undefined') {
		require = _curl;
	}

	// override executeDefFunc to override "require" deps
	priv['core'].executeDefFunc = function (def) {
		duckPunchRequire(def.require);
		return origExecuteDefFunc(def);
	};

	return true;

});
<commit_msg>now adds non-standard properties to all local require()s -- even those handed to plugins<commit_after>/** MIT License (c) copyright B Cavalier & J Hann */

/**
 * curl dojo 1.6 shim
 *
 * Licensed under the MIT License at:
 * 		http://www.opensource.org/licenses/mit-license.php
 */

/**
 * Until AMD becomes well established, there will be issues with the various
 * libs.  This one overcomes some minor issues with dojo 1.6's initial
 * foray into AMD territory. :)
 *
 * usage:
 *  curl(['curl/shim/dojo16', 'curl/domReady'])
 *  	.next(['dojo/parser'])
 *  	.then(function (parser) {
 *  		parser.parse();
 *  	});
 *
 */
var require;
define(/*=='curl/shim/dojo16',==*/ ['curl/_privileged', 'curl/domReady'], function (priv, domReady) {
"use strict";

	var _curl = priv['_curl'],
		origCreateContext = priv['core'].createContext;

	function duckPunchRequire (req) {
		// create a ready method on `require`
		if (!req['ready']){
			req['ready'] = function (cb) {
				domReady(cb);
			};
		}
		// map non-standard nameToUrl to toUrl
		if (!req['nameToUrl']) {
			req['nameToUrl'] = function (name, ext) {
				return req['toUrl'](name + (ext || ''));
			};
		}
		// dojo 1.7 has a few unchecked `require.cache` usages
		if (!req['cache']) req['cache'] = {};
		return req;
	}

	// modify global curl cuz dojo doesn't always use local `require`
	// as a dependency
	duckPunchRequire(_curl);

	// dojo 1.7 still expects a global `require`, so make sure they've got one
	if (typeof require == 'undefined') {
		require = _curl;
	}

	// override createContext to override "local require"
	priv['core'].createContext = function () {
		var def = origCreateContext.apply(this, arguments);
		duckPunchRequire(def.require);
		return def;
	};

	return true;

});
<|endoftext|>