<commit_before>import fs from 'fs'
import jsonfile from 'jsonfile'
import jsonschema from 'jsonschema'

// set indentation for jsonfile
jsonfile.spaces = 2

class ProductValidator {
  constructor (config) {
    this.dataDir = config.dataDir
    this.productSchema = config.productSchema

    this.prodFilenames = fs.readdirSync(`${this.dataDir}/prods`)
    this.nutrsFilenames = fs.readdirSync(`${this.dataDir}/nutrs`)
    this.nutrChangeFilenames = fs.readdirSync(`${this.dataDir}/nutr-change`)

    this.prods = this.prodFilenames
      .filter(filename => {
        // http://regexr.com/ is awesome! Thanks Michi!
        const filenameRegEx = /^\d.+(prod\.json)/g
        return filenameRegEx.test(filename)
      })
      .map(filename => {
        const product = jsonfile.readFileSync(`${this.dataDir}/prods/${filename}`)
        return Object.assign(product, {filename})
      })

    this.nutrs = this.nutrsFilenames.map(filename => {
      return jsonfile.readFileSync(`${this.dataDir}/nutrs/${filename}`)
    })

    this.nutrChange = this.nutrChangeFilenames.map(filename => {
      return jsonfile.readFileSync(`${this.dataDir}/nutr-change/${filename}`)
    })

    this.faos = jsonfile.readFileSync(`${this.dataDir}/fao-product-list.json`)

    this.orderedKeys = [
      ...Object.keys(this.productSchema.properties),
      'filename',
      'validationSummary'
    ]

    this.mandatoryFields = [
      'name',
      'id',
      'co2-value',
      'nutrition-id',
      'tags'
    ]

    // these optional fields will be oulled from parent if possible
    this.optionalFields = [
      'fao-product-id',
      'production-names',
      'production-values',
      'conservation-names',
      'conservation-values',
      'packaging-names',
      'packaging-values',
      'season-begin',
      'season-end',
      'unit-weight',
      'processes',
      'allergenes',
      'density',
      'alternatives'
    ]

    // concat all fields
    this.allFields = this.mandatoryFields.concat(this.optionalFields)
  }

  setProduct (product) {
    this.product = product
    return this
  }

  setProducts (products) {
    this.prods = products
    return this
  }

  orderProduct (product = this.product) {
    const orderProcesses = processes => {
      const keys = ['process', 'nutr-change-id']
      const orderedProcesses = processes.map(process => {
        if (process) {
          const orderedProcess = keys
          .map(key => {
            return {[key]: process[key]}
          })
          .reduce((process, nutrChangeId) => {
            return Object.assign(process, nutrChangeId)
          })

          return orderedProcess
        }
      })
      return orderedProcesses
    }

    const orderedPairs = this.orderedKeys
      .map(key => {
        if (key === 'processes' && product[key]) {
          return {[key]: orderProcesses(product[key])}
        } else {
          return {[key]: product[key]}
        }
      })

    this.orderedProduct = Object.assign({}, ...orderedPairs)
    return this
  }

  orderValidatedProduct (validatedProduct = this.validatedProduct) {
    this.orderedValidatedProduct = this.orderProduct(validatedProduct)
      .orderedProduct

    return this
  }

  orderValidatedProducts (validatedProducts = this.validatedProducts) {
    this.orderedValidatedProducts = validatedProducts.map(product => {
      return this.orderProduct(product).orderedProduct
    })

    return this
  }

  orderFixedProducts (fixedProducts = this.fixedProducts) {
    this.orderedFixedProducts = fixedProducts.map(product => {
      return this.orderProduct(product).orderedProduct
    })

    return this
  }

  saveOrderedValidatedProducts () {
    this.orderedValidatedProducts
      // make a copy before deleting fields!
      .map(product => Object.assign({}, product))
      .forEach(product => {
        const filename = product.filename

        delete product.filename
        delete product.validationSummary

      // write all files separately and overwrite original products
        jsonfile.writeFileSync(`${this.dataDir}/prods/${filename}`, product)
      })

    return this
  }

  saveOrderedFixedProducts () {
    // remove filename and validation Summary from products getting saved to
    // prods.all.json
    // const cleanProducts = this.orderedFixedProducts
    //   .map(product => {
    //     // make a copy before deleting fields!
    //     const cleanProduct = Object.assign({}, product)
    //
    //     delete cleanProduct.filename
    //     delete cleanProduct.validationSummary
    //
    //     return cleanProduct
    //   })

    // write all products to a single file
    // jsonfile.writeFileSync(`${this.dataDir}/prods.all.json`, cleanProducts)

    // write all products to a single file
    jsonfile.writeFileSync(
      `${this.dataDir}/prods.all.json`,
      this.orderedFixedProducts
    )

    return this
  }

  saveValidatedProduct (validatedProduct = this.validatedProduct) {
    // make a copy, before deleting fields
    const cleanProduct = Object.assign({}, validatedProduct)
    const filename = validatedProduct.filename

    delete cleanProduct.filename
    delete cleanProduct.validationSummary

    jsonfile.writeFileSync(
      `${this.dataDir}/prods/${filename}`,
      cleanProduct
    )

    return this
  }

  saveOrderedValidatedProduct (product = this.orderedValidatedProduct) {
    // make a copy, before deleting fields
    const cleanProduct = Object.assign({}, product)
    const filename = product.filename

    delete cleanProduct.filename
    delete cleanProduct.validationSummary

    jsonfile.writeFileSync(
      `${this.dataDir}/prods/${filename}`,
      cleanProduct
    )

    return this
  }

  // method to validate a product
  validateProduct (product = this.product) {
    this.setProduct(product)

    // define a validationResult
    let validationSummary = {
      parentProduct: '',
      hasNutritionId: false,
      hasNutritionChangeId: false,
      linkedNutritionIdExists: false,
      linkedNutritionChangeIdsExist: false,
      missingFields: [],
      validationErrors: []
    }

    // // There should be no schema errors once the json ui schema is
    //  implemented!
    const validationErrors = jsonschema
      .validate(product, this.productSchema).errors.map(error => {
        return error.stack.split('.')[1]
      })

    const hasValidationErrors = validationErrors.length > 0

    if (hasValidationErrors) {
      validationSummary = Object.assign(validationSummary, {validationErrors})
    }

    const missingFields = this.allFields.filter(field => {
      return !this.product.hasOwnProperty(field)
    })

    const isLinked = this.product.hasOwnProperty('linked-id')
    const fieldsMissing = missingFields.length > 0

    if (fieldsMissing) {
      validationSummary = Object.assign(validationSummary, {missingFields})
    }

    if (isLinked) {
      const parentName = this.prodFilenames.filter(filename => {
        return filename.split('-')[0] === product['linked-id']
      })

      validationSummary = Object.assign(validationSummary, {
        parentProduct: parentName[0]
      })
    }

    // does a nutrient-id field exist? Is there a corresponding file?
    const hasNutritionId = this.product.hasOwnProperty('nutrition-id')

    if (hasNutritionId) {
      const nutritionId = product['nutrition-id']
      const linkedNutritionIdExists = this.nutrs.some(nutrObj => {
        return nutrObj.id === nutritionId
      })

      if (linkedNutritionIdExists) {
        validationSummary = Object.assign(validationSummary, {
          hasNutritionId,
          linkedNutritionIdExists
        })
      } else {
        validationSummary = Object.assign(validationSummary, {
          hasNutritionId
        })
      }
    }

    // does processes field exist and does it contain nutr-change-id field(s)?
    // For each id, is there a nutr-change file with this id?
    const hasNutritionChangeId = this.product.hasOwnProperty('processes') &&
      this.product.processes[0].hasOwnProperty('nutr-change-id')

    if (hasNutritionChangeId) {
      const processes = this.product.processes
      const allNutritionChangeIds = processes.map(processesObj => {
        return processesObj['nutr-change-id']
      })

      const linkedNutritionChangeIdsExist = allNutritionChangeIds
          .every(nutritionChangeId => {
            return this.nutrChange.some(nutrChangeObj => {
              return nutrChangeObj.id === nutritionChangeId
            })
          })

      if (linkedNutritionChangeIdsExist) {
        validationSummary = Object.assign(validationSummary, {
          hasNutritionChangeId,
          linkedNutritionChangeIdsExist
        })
      } else {
        validationSummary = Object.assign(validationSummary, {
          hasNutritionChangeId
        })
      }
    }

    const validatedProduct = Object.assign(this.product, {validationSummary})

    this.validatedProduct = validatedProduct

    return this
  }

  getFieldsFromParent (validatedProduct) {
    const validationSummary = validatedProduct.validationSummary
    const missingFields = validationSummary.missingFields

    const getFieldFromParent = (parent, missingField) => {
      const validationSummaryParent = parent.validationSummary
      const isLinked = !!validationSummaryParent.parentProduct

      if (isLinked) {
        const parentProduct = this.prods.filter(product => {
          return product.filename === validationSummaryParent.parentProduct
        })[0]

        // calling this.validateProduct(parentProduct) is essential because it
        // sets the parent product as this.validatedProduct in each recursive
        // call...
        const validatedParentProduct = this.validateProduct(parentProduct).validatedProduct

        const fieldExistsInParent = parentProduct.hasOwnProperty(missingField)

        if (fieldExistsInParent) {
          return {
            [missingField]: parentProduct[missingField]
          }
        } else {
          return getFieldFromParent(validatedParentProduct, missingField)
        }
      } else {
        return {
          [missingField]: 'NOT_RESOLVABLE'
        }
      }
    }

    return missingFields.map(missingField => {
      return getFieldFromParent(validatedProduct, missingField)
    })
  }

  fixProduct (validatedProduct = this.validatedProduct) {
    let { validationSummary } = validatedProduct
    const { validationErrors } = validationSummary
    let isValid = true
    let brokenLinks = []
    const fieldsFromParent = this.getFieldsFromParent(validatedProduct)

    // check for unresolvable fields
    const unresolvableFields = fieldsFromParent
      .filter(field => {
        // get only keys for validation summary
        const key = Object.keys(field)[0]
        return field[key] === 'NOT_RESOLVABLE'
      })
      .map(field => Object.keys(field)[0])

    const resolvedFields = fieldsFromParent
      .filter(field => {
        const key = Object.keys(field)
        return field[key] !== 'NOT_RESOLVABLE'
      })

    const unresolvableMandatoryFields = unresolvableFields.filter(field => {
      return this.mandatoryFields.includes(field)
    })

    // Array.some() resolves to true if the callback returns true for any
    // of the arrays elements...
    const hasUnresolvableMandatoryFields = unresolvableMandatoryFields
      .length > 0

    if (hasUnresolvableMandatoryFields) {
      isValid = false
    }

    // check for broken links
    if (validationSummary.hasNutritionId &&
      !validationSummary.linkedNutritionIdExists) {
      brokenLinks = [...brokenLinks, 'nutrition-id']
    } else if (validationSummary.hasNutritionChangeId &&
      !validationSummary.linkedNutritionChangeIdsExist) {
      brokenLinks = [...brokenLinks, 'nutr-change-id']
    }

    const hasBrokenLinks = brokenLinks.length > 0

    if (hasBrokenLinks) {
      isValid = false
    }

    const hasValidationErrors = validationErrors.length > 0

    if (hasValidationErrors) {
      isValid = false
    }

    validationSummary = Object.assign({}, {
      isValid,
      brokenLinks,
      missingFields: unresolvableMandatoryFields,
      validationErrors
    })

    this.fixedProduct = Object.assign(validatedProduct, ...resolvedFields, {
      validationSummary
    })

    return this
  }

  validateAllProducts (products = this.prods) {
    this.validatedProducts = products.map(product => {
      return this.validateProduct(product).validatedProduct
    })

    return this
  }

  fixAllProducts (validatedProducts = this.validatedProducts) {
    this.fixedProducts = validatedProducts.map(validatedProduct => {
      return this.fixProduct(validatedProduct).fixedProduct
    })

    return this
  }
}

export default ProductValidator
<commit_msg>Adjusted mandatory and optional fields in validator according to gsheet<commit_after>import fs from 'fs'
import jsonfile from 'jsonfile'
import jsonschema from 'jsonschema'

// set indentation for jsonfile
jsonfile.spaces = 2

class ProductValidator {
  constructor (config) {
    this.dataDir = config.dataDir
    this.productSchema = config.productSchema

    this.prodFilenames = fs.readdirSync(`${this.dataDir}/prods`)
    this.nutrsFilenames = fs.readdirSync(`${this.dataDir}/nutrs`)
    this.nutrChangeFilenames = fs.readdirSync(`${this.dataDir}/nutr-change`)

    this.prods = this.prodFilenames
      .filter(filename => {
        // http://regexr.com/ is awesome! Thanks Michi!
        const filenameRegEx = /^\d.+(prod\.json)/g
        return filenameRegEx.test(filename)
      })
      .map(filename => {
        const product = jsonfile.readFileSync(`${this.dataDir}/prods/${filename}`)
        return Object.assign(product, {filename})
      })

    this.nutrs = this.nutrsFilenames.map(filename => {
      return jsonfile.readFileSync(`${this.dataDir}/nutrs/${filename}`)
    })

    this.nutrChange = this.nutrChangeFilenames.map(filename => {
      return jsonfile.readFileSync(`${this.dataDir}/nutr-change/${filename}`)
    })

    this.faos = jsonfile.readFileSync(`${this.dataDir}/fao-product-list.json`)

    this.orderedKeys = [
      ...Object.keys(this.productSchema.properties),
      'filename',
      'validationSummary'
    ]

    this.mandatoryFields = [
      'name',
      'id',
      'nutrition-id',
      'tags',
      'perishability',
      'co2-value'
    ]

    // these optional fields will be oulled from parent if possible
    this.optionalFields = [
      'fao-product-id',
      'waste-id',
      'season-begin',
      'season-end',
      'processes',
      'allergenes',
      'unit-weight',
      'density',
      'production-names',
      'production-values',
      'conservation-names',
      'conservation-values',
      'processing-names',
      'processing-values',
      'packaging-names',
      'packaging-values'
    ]

    // concat all fields
    this.allFields = this.mandatoryFields.concat(this.optionalFields)
  }

  setProduct (product) {
    this.product = product
    return this
  }

  setProducts (products) {
    this.prods = products
    return this
  }

  orderProduct (product = this.product) {
    const orderProcesses = processes => {
      const keys = ['process', 'nutr-change-id']
      const orderedProcesses = processes.map(process => {
        if (process) {
          const orderedProcess = keys
          .map(key => {
            return {[key]: process[key]}
          })
          .reduce((process, nutrChangeId) => {
            return Object.assign(process, nutrChangeId)
          })

          return orderedProcess
        }
      })
      return orderedProcesses
    }

    const orderedPairs = this.orderedKeys
      .map(key => {
        if (key === 'processes' && product[key]) {
          return {[key]: orderProcesses(product[key])}
        } else {
          return {[key]: product[key]}
        }
      })

    this.orderedProduct = Object.assign({}, ...orderedPairs)
    return this
  }

  orderValidatedProduct (validatedProduct = this.validatedProduct) {
    this.orderedValidatedProduct = this.orderProduct(validatedProduct)
      .orderedProduct

    return this
  }

  orderValidatedProducts (validatedProducts = this.validatedProducts) {
    this.orderedValidatedProducts = validatedProducts.map(product => {
      return this.orderProduct(product).orderedProduct
    })

    return this
  }

  orderFixedProducts (fixedProducts = this.fixedProducts) {
    this.orderedFixedProducts = fixedProducts.map(product => {
      return this.orderProduct(product).orderedProduct
    })

    return this
  }

  saveOrderedValidatedProducts () {
    this.orderedValidatedProducts
      // make a copy before deleting fields!
      .map(product => Object.assign({}, product))
      .forEach(product => {
        const filename = product.filename

        delete product.filename
        delete product.validationSummary

      // write all files separately and overwrite original products
        jsonfile.writeFileSync(`${this.dataDir}/prods/${filename}`, product)
      })

    return this
  }

  saveOrderedFixedProducts () {
    // remove filename and validation Summary from products getting saved to
    // prods.all.json
    // const cleanProducts = this.orderedFixedProducts
    //   .map(product => {
    //     // make a copy before deleting fields!
    //     const cleanProduct = Object.assign({}, product)
    //
    //     delete cleanProduct.filename
    //     delete cleanProduct.validationSummary
    //
    //     return cleanProduct
    //   })

    // write all products to a single file
    // jsonfile.writeFileSync(`${this.dataDir}/prods.all.json`, cleanProducts)

    // write all products to a single file
    jsonfile.writeFileSync(
      `${this.dataDir}/prods.all.json`,
      this.orderedFixedProducts
    )

    return this
  }

  saveValidatedProduct (validatedProduct = this.validatedProduct) {
    // make a copy, before deleting fields
    const cleanProduct = Object.assign({}, validatedProduct)
    const filename = validatedProduct.filename

    delete cleanProduct.filename
    delete cleanProduct.validationSummary

    jsonfile.writeFileSync(
      `${this.dataDir}/prods/${filename}`,
      cleanProduct
    )

    return this
  }

  saveOrderedValidatedProduct (product = this.orderedValidatedProduct) {
    // make a copy, before deleting fields
    const cleanProduct = Object.assign({}, product)
    const filename = product.filename

    delete cleanProduct.filename
    delete cleanProduct.validationSummary

    jsonfile.writeFileSync(
      `${this.dataDir}/prods/${filename}`,
      cleanProduct
    )

    return this
  }

  // method to validate a product
  validateProduct (product = this.product) {
    this.setProduct(product)

    // define a validationResult
    let validationSummary = {
      parentProduct: '',
      hasNutritionId: false,
      hasNutritionChangeId: false,
      linkedNutritionIdExists: false,
      linkedNutritionChangeIdsExist: false,
      missingFields: [],
      validationErrors: []
    }

    // // There should be no schema errors once the json ui schema is
    //  implemented!
    const validationErrors = jsonschema
      .validate(product, this.productSchema).errors.map(error => {
        return error.stack.split('.')[1]
      })

    const hasValidationErrors = validationErrors.length > 0

    if (hasValidationErrors) {
      validationSummary = Object.assign(validationSummary, {validationErrors})
    }

    const missingFields = this.allFields.filter(field => {
      return !this.product.hasOwnProperty(field)
    })

    const isLinked = this.product.hasOwnProperty('linked-id')
    const fieldsMissing = missingFields.length > 0

    if (fieldsMissing) {
      validationSummary = Object.assign(validationSummary, {missingFields})
    }

    if (isLinked) {
      const parentName = this.prodFilenames.filter(filename => {
        return filename.split('-')[0] === product['linked-id']
      })

      validationSummary = Object.assign(validationSummary, {
        parentProduct: parentName[0]
      })
    }

    // does a nutrient-id field exist? Is there a corresponding file?
    const hasNutritionId = this.product.hasOwnProperty('nutrition-id')

    if (hasNutritionId) {
      const nutritionId = product['nutrition-id']
      const linkedNutritionIdExists = this.nutrs.some(nutrObj => {
        return nutrObj.id === nutritionId
      })

      if (linkedNutritionIdExists) {
        validationSummary = Object.assign(validationSummary, {
          hasNutritionId,
          linkedNutritionIdExists
        })
      } else {
        validationSummary = Object.assign(validationSummary, {
          hasNutritionId
        })
      }
    }

    // does processes field exist and does it contain nutr-change-id field(s)?
    // For each id, is there a nutr-change file with this id?
    const hasNutritionChangeId = this.product.hasOwnProperty('processes') &&
      this.product.processes[0].hasOwnProperty('nutr-change-id')

    if (hasNutritionChangeId) {
      const processes = this.product.processes
      const allNutritionChangeIds = processes.map(processesObj => {
        return processesObj['nutr-change-id']
      })

      const linkedNutritionChangeIdsExist = allNutritionChangeIds
          .every(nutritionChangeId => {
            return this.nutrChange.some(nutrChangeObj => {
              return nutrChangeObj.id === nutritionChangeId
            })
          })

      if (linkedNutritionChangeIdsExist) {
        validationSummary = Object.assign(validationSummary, {
          hasNutritionChangeId,
          linkedNutritionChangeIdsExist
        })
      } else {
        validationSummary = Object.assign(validationSummary, {
          hasNutritionChangeId
        })
      }
    }

    const validatedProduct = Object.assign(this.product, {validationSummary})

    this.validatedProduct = validatedProduct

    return this
  }

  getFieldsFromParent (validatedProduct) {
    const validationSummary = validatedProduct.validationSummary
    const missingFields = validationSummary.missingFields

    const getFieldFromParent = (parent, missingField) => {
      const validationSummaryParent = parent.validationSummary
      const isLinked = !!validationSummaryParent.parentProduct

      if (isLinked) {
        const parentProduct = this.prods.filter(product => {
          return product.filename === validationSummaryParent.parentProduct
        })[0]

        // calling this.validateProduct(parentProduct) is essential because it
        // sets the parent product as this.validatedProduct in each recursive
        // call...
        const validatedParentProduct = this.validateProduct(parentProduct).validatedProduct

        const fieldExistsInParent = parentProduct.hasOwnProperty(missingField)

        if (fieldExistsInParent) {
          return {
            [missingField]: parentProduct[missingField]
          }
        } else {
          return getFieldFromParent(validatedParentProduct, missingField)
        }
      } else {
        return {
          [missingField]: 'NOT_RESOLVABLE'
        }
      }
    }

    return missingFields.map(missingField => {
      return getFieldFromParent(validatedProduct, missingField)
    })
  }

  fixProduct (validatedProduct = this.validatedProduct) {
    let { validationSummary } = validatedProduct
    const { validationErrors } = validationSummary
    let isValid = true
    let brokenLinks = []
    const fieldsFromParent = this.getFieldsFromParent(validatedProduct)

    // check for unresolvable fields
    const unresolvableFields = fieldsFromParent
      .filter(field => {
        // get only keys for validation summary
        const key = Object.keys(field)[0]
        return field[key] === 'NOT_RESOLVABLE'
      })
      .map(field => Object.keys(field)[0])

    const resolvedFields = fieldsFromParent
      .filter(field => {
        const key = Object.keys(field)
        return field[key] !== 'NOT_RESOLVABLE'
      })

    const unresolvableMandatoryFields = unresolvableFields.filter(field => {
      return this.mandatoryFields.includes(field)
    })

    // Array.some() resolves to true if the callback returns true for any
    // of the arrays elements...
    const hasUnresolvableMandatoryFields = unresolvableMandatoryFields
      .length > 0

    if (hasUnresolvableMandatoryFields) {
      isValid = false
    }

    // check for broken links
    if (validationSummary.hasNutritionId &&
      !validationSummary.linkedNutritionIdExists) {
      brokenLinks = [...brokenLinks, 'nutrition-id']
    } else if (validationSummary.hasNutritionChangeId &&
      !validationSummary.linkedNutritionChangeIdsExist) {
      brokenLinks = [...brokenLinks, 'nutr-change-id']
    }

    const hasBrokenLinks = brokenLinks.length > 0

    if (hasBrokenLinks) {
      isValid = false
    }

    const hasValidationErrors = validationErrors.length > 0

    if (hasValidationErrors) {
      isValid = false
    }

    validationSummary = Object.assign({}, {
      isValid,
      brokenLinks,
      missingFields: unresolvableMandatoryFields,
      validationErrors
    })

    this.fixedProduct = Object.assign(validatedProduct, ...resolvedFields, {
      validationSummary
    })

    return this
  }

  validateAllProducts (products = this.prods) {
    this.validatedProducts = products.map(product => {
      return this.validateProduct(product).validatedProduct
    })

    return this
  }

  fixAllProducts (validatedProducts = this.validatedProducts) {
    this.fixedProducts = validatedProducts.map(validatedProduct => {
      return this.fixProduct(validatedProduct).fixedProduct
    })

    return this
  }
}

export default ProductValidator
<|endoftext|>


<commit_before>Ext.define('doweown.view.SingleBook', {
    extend: 'Ext.List',
    xtype: 'singlebook',

    config: {
	   title: 'Search Results',
           xtype: 'list',
	   store: 'Biblio',
           pinHeaders: false,
           onItemDisclosure: function( record, btn, index ) {
                                //Ext.Msg.alert('Tap', 'Go to mobile hollis for ' + record.get('title'), Ext.emptyFn);
				this.getParent().push( {xtype: 'availbook'} );
            },
            itemTpl: '{title} - {author}
{description}'
     }

});
<commit_msg>changed title<commit_after>Ext.define('doweown.view.SingleBook', {
    extend: 'Ext.List',
    xtype: 'singlebook',
    config: {
	   //title: 'Search Results',
	   title: 'Yes, we do! :)',
           xtype: 'list',
	   store: 'Biblio',
           pinHeaders: false,
	   itemTpl: '{title} - {author}
{description}',
	   /*onItemDisclosure: function( record, btn, index ) {
                                this.getParent().push( {xtype: 'availview'} );
				this.deselectAll();
            },*/
	   listeners: {
		itemtap: function(list, index, target, record) {
			this.getParent().push( {xtype: 'availview'} );
			this.deselectAll();
		}
	    }
     }

});
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
/**
 * @module geo
 */
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/**
 * Create a new instance of mapInteractor
 *
 * @class geo.mapInteractor
 * @returns {geo.mapInteractor}
 */
//////////////////////////////////////////////////////////////////////////////
geo.mapInteractor = function (args) {
  'use strict';
  if (!(this instanceof geo.mapInteractor)) {
    return new geo.mapInteractor(args);
  }
  geo.object.call(this);

  var m_options = args || {},
      m_this = this,
      m_mouse,
      m_keyboard,
      m_state,
      $node;

  // copy the options object
  m_options = $.extend(true, {}, m_options);

  // options supported:
  // {
  //   // button that must be pressed to initiate a pan on mousedown
  //   panMoveButton: 'right' | 'left' | 'middle'
  //
  //   // modifier keys that must be pressed to initiate a pan on mousemove
  //   panMoveModifiers: ['ctrl' | 'alt' | 'meta' | 'shift' ]
  //
  //   // button that must be pressed to initiate a zoom on mousedown
  //   zoomMoveButton: 'right' | 'left' | 'middle'
  //
  //   // modifier keys that must be pressed to initiate a zoom on mousemove
  //   zoomMoveModifiers: ['ctrl' | 'alt' | 'meta' | 'shift' ]
  //
  //   // modifier keys that must be pressed to trigger a pan on wheel
  //   panWheelModifiers: [...]
  //
  //   // modifier keys that must be pressed to trigger a zoom on wheel
  //   zoomWheelModifiers: [...]
  // }

  // default mouse object
  m_mouse = {
    page: { // mouse position relative to the page
      x: 0,
      y: 0
    },
    map: { // mouse position relative to the map
      x: 0,
      y: 0
    },
    // mouse button status
    buttons: {
      left: false,
      right: false,
      middle: false
    },
    // keyboard modifier status
    modifiers: {
      alt: false,
      ctrl: false,
      shift: false,
      meta: false
    }
  };

  // default keyboard object
  // (keyboard events not implemented yet)
  m_keyboard = {
  };

  // The interactor state determines what actions are taken in response to
  // core browser events.
  //
  // i.e.
  // {
  //    'action': 'panning',  // an ongoing pan event
  //    'origin': {...},      // mouse object at the start of the action
  //    'delta': {x: *, y: *} // mouse movement since action start
  //                          // not including the current event
  //  }
  //
  //  {
  //    'action': 'zooming',  // an ongoing zoom event
  //    ...
  //  }
  m_state = {};

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Connects events to a map.  If the map is not set, then this does nothing.
   * @returns {geo.mapInteractor}
   */
  ////////////////////////////////////////////////////////////////////////////
  this._connectEvents = function () {
    if (!m_options.map) {
      return m_this;
    }

    // prevent double binding to dom elements
    m_this._disconnectEvents();

    // store the connected element
    $node = $(m_options.map.node());
    return m_this;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Disonnects events to a map.  If the map is not set, then this does nothing.
   * @returns {geo.mapInteractor}
   */
  ////////////////////////////////////////////////////////////////////////////
  this._disconnectEvents = function () {
    if (!m_options.map) {
      return m_this;
    }
    return m_this;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Sets or gets map for this interactor, adds draw region layer if needed
   *
   * @param {geo.map} newMap optional
   * @returns {geo.mapInteractorStyle|geo.map}
   */
  ////////////////////////////////////////////////////////////////////////////
  this.map = function (val) {
    if (val !== undefined) {
      m_options.map = val;
      return m_this;
    }
    m_this._connectEvents();
    return m_options.map;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Stores the current mouse position from an event
   */
  ////////////////////////////////////////////////////////////////////////////
  this._getMousePosition = function (evt) {
    var offset = $node.offset();
    m_mouse.page = {
      x: evt.pageX,
      y: evt.pageY
    };
    m_mouse.map = {
      x: evt.pageX - offset.left,
      y: evt.pageY - offset.top
    };
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Stores the current mouse button
   */
  ////////////////////////////////////////////////////////////////////////////
  this._getMouseButton = function (evt) {
    m_mouse.buttons.left = evt.which === 1;
    m_mouse.buttons.right = evt.which === 3;
    m_mouse.buttons.middle = evt.which === 2;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Stores the current keyboard modifiers
   */
  ////////////////////////////////////////////////////////////////////////////
  this._getMouseModifiers = function (evt) {
    m_mouse.modifiers.alt = evt.altKey;
    m_mouse.modifiers.ctrl = evt.ctrlKey;
    m_mouse.modifiers.meta = evt.metaKey;
    m_mouse.modifiers.shift = evt.shiftKey;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Handle event when a mouse button is pressed
   */
  ////////////////////////////////////////////////////////////////////////////
  this._handleMouseDown = function (evt) {
    m_this._getMousePosition(evt);
    m_this._getMouseButton(evt);
    m_this._getMouseModifiers(evt);

    // store the state object
    m_state = {
      action: '', // get the action by configuration
      origin: $.extend(true, {}, m_mouse),
      delta: {x: 0, y: 0}
    };

    // bind temporary handlers to document
    $(document).on('mousemove.geojs', m_this._handleMouseMoveDocument);
    $(document).on('mouseup.geojs', m_this._handleMouseUpDocument);
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Handle mouse move event
   */
  ////////////////////////////////////////////////////////////////////////////
  this._handleMouseMove = function (evt) {
    m_this._getMousePosition(evt);
    m_this._getMouseButton(evt);
    m_this._getMouseModifiers(evt);
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Handle mouse move event on the document (temporary bindings)
   */
  ////////////////////////////////////////////////////////////////////////////
  this._handleMouseMoveDocument = function (evt) {
    m_this._getMousePosition(evt);
    m_this._getMouseButton(evt);
    m_this._getMouseModifiers(evt);

    // trigger pan or zoom

    // Stop text selection in particular
    evt.preventDefault();
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Handle event when a mouse button is unpressed on the document.
   * Removes temporary bindings.
   */
  ////////////////////////////////////////////////////////////////////////////
  this._handleMouseUpDocument = function (evt) {
    m_this._getMousePosition(evt);
    m_this._getMouseButton(evt);
    m_this._getMouseModifiers(evt);

    // unbind temporary handlers on document
    $(document).off('.geojs');

    // reset the interactor state
    m_state = {};
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Handle event when a mouse button is unpressed
   */
  ////////////////////////////////////////////////////////////////////////////
  this._handleMouseUp = function (evt) {
    m_this._getMousePosition(evt);
    m_this._getMouseButton(evt);
    m_this._getMouseModifiers(evt);
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Handle mouse wheel event
   */
  ////////////////////////////////////////////////////////////////////////////
  this._handleMouseWheel = function (/*evt*/) {
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Handle double click event
   */
  ////////////////////////////////////////////////////////////////////////////
  this._handleDoubleClick = function () {
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Public method that unbinds all events
   */
  ////////////////////////////////////////////////////////////////////////////
  this.destroy = function () {
    m_this._disconnectEvents();
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Get current mouse information
   */
  ////////////////////////////////////////////////////////////////////////////
  this.mouse = function () {
    return $.extend(true, {}, m_mouse);
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Get current keyboard information
   */
  ////////////////////////////////////////////////////////////////////////////
  this.keyboard = function () {
    return $.extend(true, {}, m_keyboard);
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Get the current interactor state
   */
  ////////////////////////////////////////////////////////////////////////////
  this.state = function () {
    return $.extend(true, {}, m_state);
  };

  this._connectEvents();
  return this;
};

inherit(geo.mapInteractor, geo.object);
<commit_msg>connecting core mouse events<commit_after>//////////////////////////////////////////////////////////////////////////////
/**
 * @module geo
 */
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/**
 * Create a new instance of mapInteractor
 *
 * @class geo.mapInteractor
 * @returns {geo.mapInteractor}
 */
//////////////////////////////////////////////////////////////////////////////
geo.mapInteractor = function (args) {
  'use strict';
  if (!(this instanceof geo.mapInteractor)) {
    return new geo.mapInteractor(args);
  }
  geo.object.call(this);

  var m_options = args || {},
      m_this = this,
      m_mouse,
      m_keyboard,
      m_state,
      $node;

  // Helper method to decide if the current button/modifiers match a set of
  // conditions.
  // button: 'left' | 'right' | 'middle'
  // modifiers: [ 'alt' | 'meta' | 'ctrl' | 'shift' ]
  function eventMatch(button, modifiers) {
    /* jshint -W018 */
    return (button === null || !m_mouse.buttons[button]) &&
      !!m_mouse.modifiers.alt   === !!modifiers.alt   &&
      !!m_mouse.modifiers.meta  === !!modifiers.meta  &&
      !!m_mouse.modifiers.shift === !!modifiers.shift &&
      !!m_mouse.modifiers.ctrl  === !!modifiers.ctrl;
    /* jshint +W018 */
  }

  // copy the options object with defaults
  m_options = $.extend(
    true,
    {
      panMoveButton: 'left',
      panMoveModifiers: {},
      zoomMoveButton: 'right',
      zoomMoveModifiers: {},
      panWheelEnabled: false,
      panWheelModifiers: {},
      zoomWheelEnabled: true,
      zoomWheelModifiers: {}
    },
    m_options
  );

  // options supported:
  // {
  //   // button that must be pressed to initiate a pan on mousedown
  //   panMoveButton: 'right' | 'left' | 'middle'
  //
  //   // modifier keys that must be pressed to initiate a pan on mousemove
  //   panMoveModifiers: { 'ctrl' | 'alt' | 'meta' | 'shift' }
  //
  //   // button that must be pressed to initiate a zoom on mousedown
  //   zoomMoveButton: 'right' | 'left' | 'middle'
  //
  //   // modifier keys that must be pressed to initiate a zoom on mousemove
  //   zoomMoveModifiers: { 'ctrl' | 'alt' | 'meta' | 'shift' }
  //
  //   // modifier keys that must be pressed to trigger a pan on wheel
  //   panWheelModifiers: {...}
  //
  //   // modifier keys that must be pressed to trigger a zoom on wheel
  //   zoomWheelModifiers: {...}
  // }

  // default mouse object
  m_mouse = {
    page: { // mouse position relative to the page
      x: 0,
      y: 0
    },
    map: { // mouse position relative to the map
      x: 0,
      y: 0
    },
    geo: null, // geographic coordinates, when available
    // mouse button status
    buttons: {
      left: false,
      right: false,
      middle: false
    },
    // keyboard modifier status
    modifiers: {
      alt: false,
      ctrl: false,
      shift: false,
      meta: false
    }
  };

  // default keyboard object
  // (keyboard events not implemented yet)
  m_keyboard = {
  };

  // The interactor state determines what actions are taken in response to
  // core browser events.
  //
  // i.e.
  // {
  //    'action': 'pan',      // an ongoing pan event
  //    'origin': {...},      // mouse object at the start of the action
  //    'delta': {x: *, y: *} // mouse movement since action start
  //                          // not including the current event
  //  }
  //
  //  {
  //    'action': 'zoom',  // an ongoing zoom event
  //    ...
  //  }
  m_state = {};

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Connects events to a map.  If the map is not set, then this does nothing.
   * @returns {geo.mapInteractor}
   */
  ////////////////////////////////////////////////////////////////////////////
  this._connectEvents = function () {
    if (!m_options.map) {
      return m_this;
    }

    // prevent double binding to dom elements
    m_this._disconnectEvents();

    // store the connected element
    $node = $(m_options.map.node());
    return m_this;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Disonnects events to a map.  If the map is not set, then this does nothing.
   * @returns {geo.mapInteractor}
   */
  ////////////////////////////////////////////////////////////////////////////
  this._disconnectEvents = function () {
    if (!m_options.map) {
      return m_this;
    }
    return m_this;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Sets or gets map for this interactor, adds draw region layer if needed
   *
   * @param {geo.map} newMap optional
   * @returns {geo.mapInteractorStyle|geo.map}
   */
  ////////////////////////////////////////////////////////////////////////////
  this.map = function (val) {
    if (val !== undefined) {
      m_options.map = val;
      return m_this;
    }
    m_this._connectEvents();
    return m_options.map;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Stores the current mouse position from an event
   */
  ////////////////////////////////////////////////////////////////////////////
  this._getMousePosition = function (evt) {
    var offset = $node.offset(), map = m_this.map();
    m_mouse.page = {
      x: evt.pageX,
      y: evt.pageY
    };
    m_mouse.map = {
      x: evt.pageX - offset.left,
      y: evt.pageY - offset.top
    };

    // Always invalidate the last lat/lng position
    m_mouse.geo = null;

    // If connected to a map do the projection
    if (map) {
      m_mouse.geo = map.displayToGcs(m_mouse.map);
    }
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Stores the current mouse button
   */
  ////////////////////////////////////////////////////////////////////////////
  this._getMouseButton = function (evt) {
    if (evt.which === 1)
      m_mouse.buttons.left = evt.type !== 'mouseup';
    else if (evt.which === 3) {
      m_mouse.buttons.right = evt.type !== 'mouseup';
    } else if (evt.which === 2) {
      m_mouse.buttons.middle = evt.type !== 'mouseup';
    }
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Stores the current keyboard modifiers
   */
  ////////////////////////////////////////////////////////////////////////////
  this._getMouseModifiers = function (evt) {
    m_mouse.modifiers.alt = evt.altKey;
    m_mouse.modifiers.ctrl = evt.ctrlKey;
    m_mouse.modifiers.meta = evt.metaKey;
    m_mouse.modifiers.shift = evt.shiftKey;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Handle event when a mouse button is pressed
   */
  ////////////////////////////////////////////////////////////////////////////
  this._handleMouseDown = function (evt) {
    var action = null;

    m_this._getMousePosition(evt);
    m_this._getMouseButton(evt);
    m_this._getMouseModifiers(evt);

    if (eventMatch(m_options.panMoveButton, m_options.panMoveModifiers)) {
      action = 'pan';
    } else if (eventMatch(m_options.zoomMoveButton, m_options.zoomMoveModifiers)) {
      action = 'zoom';
    }

    if (action) {
      // store the state object
      m_state = {
        action: action,
        origin: $.extend(true, {}, m_mouse),
        delta: {x: 0, y: 0}
      };

      // bind temporary handlers to document
      $(document).on('mousemove.geojs', m_this._handleMouseMoveDocument);
      $(document).on('mouseup.geojs', m_this._handleMouseUpDocument);
    }

  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Handle mouse move event
   */
  ////////////////////////////////////////////////////////////////////////////
  this._handleMouseMove = function (evt) {
    if (m_state.action) {
      // If currently performing a navigation action, the mouse
      // coordinates will be captured by the document handler.
      return;
    }
    m_this._getMousePosition(evt);
    m_this._getMouseButton(evt);
    m_this._getMouseModifiers(evt);
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Handle mouse move event on the document (temporary bindings)
   */
  ////////////////////////////////////////////////////////////////////////////
  this._handleMouseMoveDocument = function (evt) {
    var dx, dy;
    m_this._getMousePosition(evt);
    m_this._getMouseButton(evt);
    m_this._getMouseModifiers(evt);

    if (!m_state.action) {
      // This shouldn't happen
      console.log('WARNING: Invalid state in mapInteractor.');
      return;
    }

    // calculate the delta from the origin point to avoid
    // accumulation of floating point errors
    dx = m_mouse.map.x - m_state.origin.x - m_state.delta.x;
    dy = m_mouse.map.y - m_state.origin.y - m_state.delta.y;
    m_state.delta.x += dx;
    m_state.delta.y += dy;

    // trigger pan or zoom
    m_this.map().geoTrigger(
      geo.events[m_state.action],
      {
        screenDelta: {
          x: dx,
          y: dy
        },
        eventType: geo.events[m_state.action],
        mouseOrigin: m_state.origin,
        totalDelta: m_state.delta,
        mouseCurrent: m_mouse
      }
    );

    // Stop text selection in particular
    evt.preventDefault();
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Handle event when a mouse button is unpressed on the document.
   * Removes temporary bindings.
   */
  ////////////////////////////////////////////////////////////////////////////
  this._handleMouseUpDocument = function (evt) {
    m_this._getMousePosition(evt);
    m_this._getMouseButton(evt);
    m_this._getMouseModifiers(evt);

    // unbind temporary handlers on document
    $(document).off('.geojs');

    // reset the interactor state
    m_state = {};
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Handle event when a mouse button is unpressed
   */
  ////////////////////////////////////////////////////////////////////////////
  this._handleMouseUp = function (evt) {
    m_this._getMousePosition(evt);
    m_this._getMouseButton(evt);
    m_this._getMouseModifiers(evt);
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Handle mouse wheel event
   */
  ////////////////////////////////////////////////////////////////////////////
  this._handleMouseWheel = function (evt) {
    m_this._getMouseModifiers(evt);

    if (m_options.panWheelEnabled &&
        eventMatch(null, m_options.panWheelModifiers)) {
      // trigger pan event
      // dx = evt.deltaX * evt.deltaFactor
      // dy = evt.deltaY * evt.deltaFactor
    } else if (m_options.zoomWheelEnabled &&
               eventMatch(null, m_options.zoomWheelModifiers)) {
      // trigger zoom event
      // dy = evt.deltaY * evt.deltaFactor
    }
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Handle double click event
   */
  ////////////////////////////////////////////////////////////////////////////
  this._handleDoubleClick = function () {
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Public method that unbinds all events
   */
  ////////////////////////////////////////////////////////////////////////////
  this.destroy = function () {
    m_this._disconnectEvents();
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Get current mouse information
   */
  ////////////////////////////////////////////////////////////////////////////
  this.mouse = function () {
    return $.extend(true, {}, m_mouse);
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Get current keyboard information
   */
  ////////////////////////////////////////////////////////////////////////////
  this.keyboard = function () {
    return $.extend(true, {}, m_keyboard);
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Get the current interactor state
   */
  ////////////////////////////////////////////////////////////////////////////
  this.state = function () {
    return $.extend(true, {}, m_state);
  };

  this._connectEvents();
  return this;
};

inherit(geo.mapInteractor, geo.object);
<|endoftext|>


<commit_before>(function (CS) {
    var definition = {
        typeName: 'putvalue',
        datasourceBehavior: CS.DatasourceBehaviors.Single,
        getDefaultConfig: function() {
            return {
                DataShape: 'Value',
                Height: 150,
                Width: 150,
                TextColor: 'rgb(255,255,255)',
                ShowLabel: true,
                ShowTime: true,
                ShowPutValue: true
            };
        },
        configOptions: function () {
            return [{
                title: 'Format Symbol',
                mode: 'format'
            }];
        },
        init: init
    };

    function init(scope) {
        function onUpdate(data) {
            if(data) {
                scope.value = data.Value;
                scope.time = data.Time;
                if(data.Path){
                    scope.path = data.Path;
                }
                if(data.Label) {
                    scope.label = data.Label;
                }
            }
        }
        scope.putvalue = function() {
            //piwebapiserver machine name - Normally PI Coresight machine contains PI Web API. So localhost should be fine.
            var piwebapiaddress = "localhost";
            //scope.path contains pi:\\servername\tagname or af:\\servername\databasename\element...|attribute
            var ini = scope.path.substr(0,3);
            var orgpath = scope.path.substr(3,10000);
            //To double the backslash -  \\\\servername\\tagname
            var path = orgpath.replace(/\\|\\/g,"\\\\");
            if(ini=="pi:"){
                var urladdress = "\"https://" + piwebapiaddress + "/piwebapi/points?path="+path+"\"";
            }
            else if(ini=="af:"){
                var urladdress = "\"https://" + piwebapiaddress + "/piwebapi/attributes?path="+path+"\"";
            }
            //Get text box value
             //var boxval = new String([ $("#box").val() ], { "type" : "text/plain" });
//             $(‘[name=data]’)[i].value
             var boxval = new String(scope.config.Box, { "type" : "text/plain" });

             var jsonval = '"{Value:' + boxval + '}"';
             // Create contents of PI Web API batch request
             var contents = '{"GetWebID":{"Method": "GET","Resource": '+ urladdress + '},"WriteValuetoPI":{"Method":"POST","Resource": "{0}","Content":' + jsonval + ',"Parameters": ["$.GetWebID.Content.Links.Value"],"ParentIds": ["GetWebID"]}}';

            //PI Web API Request
            var batchurl = "https://localhost/piwebapi/batch";
            var xhr= new XMLHttpRequest();
            //true = Async call
            xhr.open("POST",batchurl,true);
            //Set credential for Kerberos
            xhr.withCredentials = true;
            xhr.setRequestHeader('Content-Type','application/json');
            //Send request
            xhr.send(contents);
        };
        return { dataUpdate: onUpdate };
    }
    CS.symbolCatalog.register(definition);
})(window.Coresight);<commit_msg>Comments edited<commit_after>(function (CS) {
    var definition = {
        typeName: 'putvalue',
        datasourceBehavior: CS.DatasourceBehaviors.Single,
        getDefaultConfig: function() {
            return {
                DataShape: 'Value',
                Height: 150,
                Width: 150,
                TextColor: 'rgb(255,255,255)',
                ShowLabel: true,
                ShowTime: true,
                ShowPutValue: true
            };
        },
        configOptions: function () {
            return [{
                title: 'Format Symbol',
                mode: 'format'
            }];
        },
        init: init
    };
    function init(scope) {
        function onUpdate(data) {
            if(data) {
                scope.value = data.Value;
                scope.time = data.Time;
                if(data.Path){
                    scope.path = data.Path;
                }
                if(data.Label) {
                    scope.label = data.Label;
                }
            }
        }
        scope.putvalue = function() {
            //piwebapiserver machine name - Normally PI Coresight machine contains PI Web API. So localhost should be fine.
            var piwebapiaddress = "localhost";
            //scope.path contains pi:\\servername\tagname or af:\\servername\databasename\element...|attribute
            var ini = scope.path.substr(0,3);
            var orgpath = scope.path.substr(3,10000);
            //To double the backslash -  \\\\servername\\tagname
            var path = orgpath.replace(/\\|\\/g,"\\\\");
            if(ini=="pi:"){
                var urladdress = "\"https://" + piwebapiaddress + "/piwebapi/points?path="+path+"\"";
            }
            else if(ini=="af:"){
                var urladdress = "\"https://" + piwebapiaddress + "/piwebapi/attributes?path="+path+"\"";
            }
            //Get text box value
            var boxval = new String(scope.config.Box, { "type" : "text/plain" });
            //Create value contents as json
            var jsonval = '"{Value:' + boxval + '}"';
            // Create contents of PI Web API batch request
            var contents = '{"GetWebID":{"Method": "GET","Resource": '+ urladdress + '},"WriteValuetoPI":{"Method":"POST","Resource": "{0}","Content":' + jsonval + ',"Parameters": ["$.GetWebID.Content.Links.Value"],"ParentIds": ["GetWebID"]}}';

            //PI Web API Request
            var batchurl = "https://localhost/piwebapi/batch";
            var xhr= new XMLHttpRequest();
            //true = Async call
            xhr.open("POST",batchurl,true);
            //Set credential for Kerberos
            xhr.withCredentials = true;
            xhr.setRequestHeader('Content-Type','application/json');
            //Send request
            xhr.send(contents);
        };
        return { dataUpdate: onUpdate };
    }
    CS.symbolCatalog.register(definition);
})(window.Coresight);<|endoftext|>


<commit_before>// Edit from https://github.com/zalmoxisus/remote-redux-devtools/blob/master/src/devTools.js

import { stringify, parse } from 'jsan';
import instrument from 'redux-devtools-instrument';
import { evalAction, getActionsArray } from 'remotedev-utils';
import { isFiltered, filterStagedActions, filterState } from 'remotedev-utils/lib/filters';

function configureStore(next, subscriber, options) {
  return instrument(subscriber, options)(next);
}

const instances = { /* id, name, store */ };

let lastAction;
let filters;
let isExcess;
let listenerAdded;
let actionCreators;
let stateSanitizer;
let actionSanitizer;
let locked;
let paused;

function generateId(id) {
  return id || Math.random().toString(36).substr(2);
}

function init(options) {
  if (options.filters) {
    filters = options.filters;
  }
  if (options.actionCreators) {
    actionCreators = () => getActionsArray(options.actionCreators);
  }
  stateSanitizer = options.stateSanitizer;
  actionSanitizer = options.actionSanitizer;
}

function getLiftedState(store) {
  return filterStagedActions(store.liftedStore.getState());
}

function relay(type, state, instance, action, nextActionId) {
  if (filters && isFiltered(action, filters)) return;
  const message = {
    type,
    id: instance.id,
    name: instance.name,
  };
  if (state) {
    message.payload = type === 'ERROR' ?
      state :
      stringify(filterState(state, type, filters, stateSanitizer, actionSanitizer, nextActionId));
  }
  if (type === 'ACTION') {
    message.action = stringify(
      !actionSanitizer ? action : actionSanitizer(action.action, nextActionId - 1)
    );
    message.isExcess = isExcess;
    message.nextActionId = nextActionId;
  } else if (action) {
    message.action = stringify(action);
  }
  postMessage({ __IS_REDUX_NATIVE_MESSAGE__: true, content: message });
}

function dispatchRemotely(action, id) {
  try {
    const result = evalAction(action, actionCreators);
    const { store } = instances[id];
    store.dispatch(result);
  } catch (e) {
    relay('ERROR', e.message, instances[id]);
  }
}

function handleMessages(message) {
  const { id, instanceId, type, action, state, toAll } = message;
  if (toAll) {
    Object.keys(instances).forEach(key => {
      handleMessages({ ...message, id: key, toAll: false });
    });
    return;
  }

  const { store } = instances[id || instanceId];
  if (type === 'IMPORT') {
    store.liftedStore.dispatch({
      type: 'IMPORT_STATE',
      nextLiftedState: parse(state),
    });
  }
  if (type === 'UPDATE' || type === 'IMPORT') {
    relay('STATE', getLiftedState(store), instances[id]);
  }
  if (type === 'ACTION') {
    dispatchRemotely(action, id);
  } else if (type === 'DISPATCH') {
    store.liftedStore.dispatch(action);
  }
}

function start(instance) {
  if (!listenerAdded) {
    self.addEventListener('message', message => {
      const { method, content } = message.data;
      if (method === 'emitReduxMessage') {
        handleMessages(content);
      }
    });
    listenerAdded = true;
  }

  if (typeof actionCreators === 'function') actionCreators = actionCreators();
  relay('STATE', getLiftedState(instance.store), instance, actionCreators);
}

function checkForReducerErrors(liftedState, instance) {
  if (liftedState.computedStates[liftedState.currentStateIndex].error) {
    relay('STATE', filterStagedActions(liftedState, filters), instance);
    return true;
  }
  return false;
}

function monitorReducer(state = {}, action) {
  lastAction = action.type;
  return state;
}

function handleChange(state, liftedState, maxAge, instance) {
  if (checkForReducerErrors(liftedState, instance)) return;

  if (lastAction === 'PERFORM_ACTION') {
    const nextActionId = liftedState.nextActionId;
    const liftedAction = liftedState.actionsById[nextActionId - 1];
    relay('ACTION', state, instance, liftedAction, nextActionId);
    if (!isExcess && maxAge) isExcess = liftedState.stagedActionIds.length >= maxAge;
  } else {
    if (lastAction === 'JUMP_TO_STATE') return;
    if (lastAction === 'PAUSE_RECORDING') {
      paused = liftedState.isPaused;
    } else if (lastAction === 'LOCK_CHANGES') {
      locked = liftedState.isLocked;
    }
    if (paused || locked) {
      if (lastAction) lastAction = undefined;
      else return;
    }
    relay('STATE', filterStagedActions(liftedState, filters), instance);
  }
}

export default function devToolsEnhancer(options = {}) {
  init(options);

  const defaultName = global.require ? global.require('Platform').OS : 'default';
  const {
    name,
    maxAge = 30,
    shouldHotReload,
    shouldRecordChanges,
    shouldStartLocked,
    pauseActionType,
  } = options;
  const id = generateId(options.instanceId);

  return next => (reducer, initialState) => {
    const store = configureStore(
      next, monitorReducer, {
        maxAge,
        shouldHotReload,
        shouldRecordChanges,
        shouldStartLocked,
        pauseActionType: pauseActionType || '@@PAUSED',
      }
    )(reducer, initialState);

    instances[id] = {
      name: name || `${defaultName}-${id}`,
      id,
      store,
    };

    start(instances[id]);
    store.subscribe(() => {
      handleChange(store.getState(), store.liftedStore.getState(), maxAge, instances[id]);
    });
    return store;
  };
}

const preEnhancer = instanceId => next =>
  (reducer, initialState, enhancer) => {
    const store = next(reducer, initialState, enhancer);

    if (instances[instanceId]) {
      instances[instanceId].store = store;
    }
    return {
      ...store,
      dispatch: (action) => (
        locked ? action : store.dispatch(action)
      ),
    };
  };

devToolsEnhancer.updateStore = (newStore, instanceId) => {
  console.warn(
    '`reduxNativeDevTools.updateStore` is deprecated use `reduxNativeDevToolsCompose` instead:',
    'https://github.com/jhen0409/react-native-debugger#advanced-store-setup'
  );

  const keys = Object.keys(instances);
  if (!keys.length) return;

  if (keys.length > 1 && !instanceId) {
    console.warn(
      'You have multiple stores,',
      'please provide `instanceId` argument (`updateStore(store, instanceId)`)'
    );
  }
  if (instanceId) {
    const instance = instances[instanceId];
    if (!instance) return;
    instance.store = newStore;
  } else {
    instances[keys[0]].store = newStore;
  }
};

const compose = options => (...funcs) => (...args) => {
  const instanceId = generateId(options.instanceId);
  return [preEnhancer(instanceId), ...funcs].reduceRight(
    (composed, f) => f(composed), devToolsEnhancer({ ...options, instanceId })(...args)
  );
};

export function composeWithDevTools(...funcs) {
  if (funcs.length === 0) {
    return devToolsEnhancer();
  }
  if (funcs.length === 1 && typeof funcs[0] === 'object') {
    return compose(funcs[0]);
  }
  return compose({})(...funcs);
}
<commit_msg>Fix filters, actionCreators, sanitizer for each instance<commit_after>// Edit from https://github.com/zalmoxisus/remote-redux-devtools/blob/master/src/devTools.js

import { stringify, parse } from 'jsan';
import instrument from 'redux-devtools-instrument';
import { evalAction, getActionsArray } from 'remotedev-utils';
import { isFiltered, filterStagedActions, filterState } from 'remotedev-utils/lib/filters';

function configureStore(next, subscriber, options) {
  return instrument(subscriber, options)(next);
}

const instances = { /* id, name, store */ };

let lastAction;
let isExcess;
let listenerAdded;
let locked;
let paused;

function generateId(id) {
  return id || Math.random().toString(36).substr(2);
}

function getLiftedState(store) {
  return filterStagedActions(store.liftedStore.getState());
}

function relay(type, state, instance, action, nextActionId) {
  const { filters, stateSanitizer, actionSanitizer } = instance;

  if (filters && !Array.isArray(action) && isFiltered(action, filters)) return;
  const message = {
    type,
    id: instance.id,
    name: instance.name,
  };
  if (state) {
    message.payload = type === 'ERROR' ?
      state :
      stringify(filterState(state, type, filters, stateSanitizer, actionSanitizer, nextActionId));
  }
  if (type === 'ACTION') {
    message.action = stringify(
      !actionSanitizer ? action : actionSanitizer(action.action, nextActionId - 1)
    );
    message.isExcess = isExcess;
    message.nextActionId = nextActionId;
  } else if (action) {
    message.action = stringify(action);
  }
  postMessage({ __IS_REDUX_NATIVE_MESSAGE__: true, content: message });
}

function dispatchRemotely(action, id) {
  try {
    const { store, actionCreators } = instances[id];
    const result = evalAction(action, actionCreators);
    store.dispatch(result);
  } catch (e) {
    relay('ERROR', e.message, instances[id]);
  }
}

function handleMessages(message) {
  const { id, instanceId, type, action, state, toAll } = message;
  if (toAll) {
    Object.keys(instances).forEach(key => {
      handleMessages({ ...message, id: key, toAll: false });
    });
    return;
  }

  const { store } = instances[id || instanceId];
  if (type === 'IMPORT') {
    store.liftedStore.dispatch({
      type: 'IMPORT_STATE',
      nextLiftedState: parse(state),
    });
  }
  if (type === 'UPDATE' || type === 'IMPORT') {
    relay('STATE', getLiftedState(store), instances[id]);
  }
  if (type === 'ACTION') {
    dispatchRemotely(action, id);
  } else if (type === 'DISPATCH') {
    store.liftedStore.dispatch(action);
  }
}

function start(instance) {
  if (!listenerAdded) {
    self.addEventListener('message', message => {
      const { method, content } = message.data;
      if (method === 'emitReduxMessage') {
        handleMessages(content);
      }
    });
    listenerAdded = true;
  }
  const { store, actionCreators } = instance;
  if (typeof actionCreators === 'function') {
    instance.actionCreators = actionCreators();
  }
  relay('STATE', getLiftedState(store), instance, instance.actionCreators);
}

function checkForReducerErrors(liftedState, instance) {
  if (liftedState.computedStates[liftedState.currentStateIndex].error) {
    relay('STATE', filterStagedActions(liftedState, instance.filters), instance);
    return true;
  }
  return false;
}

function monitorReducer(state = {}, action) {
  lastAction = action.type;
  return state;
}

function handleChange(state, liftedState, maxAge, instance) {
  if (checkForReducerErrors(liftedState, instance)) return;

  if (lastAction === 'PERFORM_ACTION') {
    const nextActionId = liftedState.nextActionId;
    const liftedAction = liftedState.actionsById[nextActionId - 1];
    relay('ACTION', state, instance, liftedAction, nextActionId);
    if (!isExcess && maxAge) isExcess = liftedState.stagedActionIds.length >= maxAge;
  } else {
    if (lastAction === 'JUMP_TO_STATE') return;
    if (lastAction === 'PAUSE_RECORDING') {
      paused = liftedState.isPaused;
    } else if (lastAction === 'LOCK_CHANGES') {
      locked = liftedState.isLocked;
    }
    if (paused || locked) {
      if (lastAction) lastAction = undefined;
      else return;
    }
    relay('STATE', filterStagedActions(liftedState, instance.filters), instance);
  }
}

export default function devToolsEnhancer(options = {}) {
  const defaultName = global.require ? global.require('Platform').OS : 'default';
  const {
    name,
    maxAge = 30,
    shouldHotReload,
    shouldRecordChanges,
    shouldStartLocked,
    pauseActionType = '@@PAUSED',
    actionCreators,
    filters,
    actionSanitizer,
    stateSanitizer,
  } = options;
  const id = generateId(options.instanceId);

  return next => (reducer, initialState) => {
    const store = configureStore(
      next, monitorReducer, {
        maxAge,
        shouldHotReload,
        shouldRecordChanges,
        shouldStartLocked,
        pauseActionType,
      }
    )(reducer, initialState);

    instances[id] = {
      name: name || `${defaultName}-${id}`,
      id,
      store,
      filters,
      actionCreators: actionCreators && (() => getActionsArray(actionCreators)),
      stateSanitizer,
      actionSanitizer,
    };

    start(instances[id]);
    store.subscribe(() => {
      handleChange(store.getState(), store.liftedStore.getState(), maxAge, instances[id]);
    });
    return store;
  };
}

const preEnhancer = instanceId => next =>
  (reducer, initialState, enhancer) => {
    const store = next(reducer, initialState, enhancer);

    if (instances[instanceId]) {
      instances[instanceId].store = store;
    }
    return {
      ...store,
      dispatch: (action) => (
        locked ? action : store.dispatch(action)
      ),
    };
  };

devToolsEnhancer.updateStore = (newStore, instanceId) => {
  console.warn(
    '`reduxNativeDevTools.updateStore` is deprecated use `reduxNativeDevToolsCompose` instead:',
    'https://github.com/jhen0409/react-native-debugger#advanced-store-setup'
  );

  const keys = Object.keys(instances);
  if (!keys.length) return;

  if (keys.length > 1 && !instanceId) {
    console.warn(
      'You have multiple stores,',
      'please provide `instanceId` argument (`updateStore(store, instanceId)`)'
    );
  }
  if (instanceId) {
    const instance = instances[instanceId];
    if (!instance) return;
    instance.store = newStore;
  } else {
    instances[keys[0]].store = newStore;
  }
};

const compose = options => (...funcs) => (...args) => {
  const instanceId = generateId(options.instanceId);
  return [preEnhancer(instanceId), ...funcs].reduceRight(
    (composed, f) => f(composed), devToolsEnhancer({ ...options, instanceId })(...args)
  );
};

export function composeWithDevTools(...funcs) {
  if (funcs.length === 0) {
    return devToolsEnhancer();
  }
  if (funcs.length === 1 && typeof funcs[0] === 'object') {
    return compose(funcs[0]);
  }
  return compose({})(...funcs);
}
<|endoftext|>


<commit_before>function assert(bool, message) {
  if (!bool) throw "Assertion failed! " + (message || "")
}
function isArray(o) {
  return o && o.constructor === Array
}

function indent(text) {
  return text
    .split("\n")
    .map(function(line) {
      return "  " + line
    })
    .join("\n")
}

function maybeNumber(v) {
  v = "" + v
  var n = parseInt(v)
  if (!isNaN(n)) {
    return n
  }
  var f = parseFloat(v)
  if (!isNaN(f)) {
    return f
  }
  return v
}

var {
  blocksById,
  parseSpec,
  inputPat,
  parseInputNumber,
  iconPat,
  rtlLanguages,
  unicodeIcons,
  english,
  blockName,
} = require("./blocks.js")

/* Label */

var Label = function(value, cls) {
  this.value = value
  this.cls = cls || ""
  this.el = null
  this.height = 12
  this.metrics = null
  this.x = 0
}
Label.prototype.isLabel = true

Label.prototype.stringify = function() {
  if (this.value === "<" || this.value === ">") return this.value
  return this.value.replace(/([<>[\](){}])/g, "\\$1")
}

/* Icon */

var Icon = function(name) {
  this.name = name
  this.isArrow = name === "loopArrow"

  assert(Icon.icons[name], "no info for icon " + name)
}
Icon.prototype.isIcon = true

Icon.icons = {
  greenFlag: true,
  turnLeft: true,
  turnRight: true,
  loopArrow: true,
  addInput: true,
  delInput: true,
}

Icon.prototype.stringify = function() {
  return unicodeIcons["@" + this.name] || ""
}

/* Input */

var Input = function(shape, value, menu) {
  this.shape = shape
  this.value = value
  this.menu = menu || null

  this.isRound = shape === "number" || shape === "number-dropdown"
  this.isBoolean = shape === "boolean"
  this.isStack = shape === "stack"
  this.isInset =
    shape === "boolean" || shape === "stack" || shape === "reporter"
  this.isColor = shape === "color"
  this.hasArrow = shape === "dropdown" || shape === "number-dropdown"
  this.isDarker =
    shape === "boolean" || shape === "stack" || shape === "dropdown"
  this.isSquare =
    shape === "string" || shape === "color" || shape === "dropdown"

  this.hasLabel = !(this.isColor || this.isInset)
  this.label = this.hasLabel ? new Label(value, "literal-" + this.shape) : null
  this.x = 0
}
Input.prototype.isInput = true

Input.prototype.stringify = function() {
  if (this.isColor) {
    assert(this.value[0] === "#")
    return "[" + this.value + "]"
  }
  var text = (this.value ? "" + this.value : "")
    .replace(/ v$/, " \\v")
    .replace(/([\]\\])/g, "\\$1")
  if (this.hasArrow) text += " v"
  return this.isRound
    ? "(" + text + ")"
    : this.isSquare
      ? "[" + text + "]"
      : this.isBoolean ? "<>" : this.isStack ? "{}" : text
}

Input.prototype.translate = function(lang) {
  if (this.hasArrow) {
    var value = this.menu || this.value
    this.value = value // TODO translate dropdown value
    this.label = new Label(this.value, "literal-" + this.shape)
  }
}

/* Block */

var Block = function(info, children, comment) {
  assert(info)
  this.info = Object.assign({}, info)
  this.children = children
  this.comment = comment || null
  this.diff = null

  var shape = this.info.shape
  this.isHat = shape === "hat" || shape === "cat" || shape === "define-hat"
  this.hasPuzzle = shape === "stack" || shape === "hat" || shape === "cat"
  this.isFinal = /cap/.test(shape)
  this.isCommand = shape === "stack" || shape === "cap" || /block/.test(shape)
  this.isOutline = shape === "outline"
  this.isReporter = shape === "reporter"
  this.isBoolean = shape === "boolean"

  this.isRing = shape === "ring"
  this.hasScript = /block/.test(shape)
  this.isElse = shape === "celse"
  this.isEnd = shape === "cend"
}
Block.prototype.isBlock = true

Block.prototype.stringify = function(extras) {
  var firstInput = null
  var checkAlias = false
  var text = this.children
    .map(function(child) {
      if (child.isIcon) checkAlias = true
      if (!firstInput && !(child.isLabel || child.isIcon)) firstInput = child
      return child.isScript
        ? "\n" + indent(child.stringify()) + "\n"
        : child.stringify().trim() + " "
    })
    .join("")
    .trim()

  var lang = this.info.language
  if (checkAlias && lang && this.info.selector) {
    var type = blocksById[this.info.id]
    var spec = type.spec
    var alias = lang.nativeAliases[type.spec]
    if (alias) {
      // TODO make translate() not in-place, and use that
      if (inputPat.test(alias) && firstInput) {
        alias = alias.replace(inputPat, firstInput.stringify())
      }
      return alias
    }
  }

  var overrides = extras || ""
  if (
    this.info.categoryIsDefault === false ||
    (this.info.category === "custom-arg" &&
      (this.isReporter || this.isBoolean)) ||
    (this.info.category === "custom" && this.info.shape === "stack")
  ) {
    if (overrides) overrides += " "
    overrides += this.info.category
  }
  if (overrides) {
    text += " :: " + overrides
  }
  return this.hasScript
    ? text + "\nend"
    : this.info.shape === "reporter"
      ? "(" + text + ")"
      : this.info.shape === "boolean" ? "<" + text + ">" : text
}

Block.prototype.translate = function(lang, isShallow) {
  if (!lang) throw new Error("Missing language")

  var id = this.info.id
  if (!id) return

  if (id === "PROCEDURES_DEFINITION") {
    // Find the first 'outline' child (there should be exactly one).
    const outline = this.children.find(child => child.isOutline)

    this.children = []
    for (const word of lang.definePrefix) {
      this.children.push(new Label(word))
    }
    this.children.push(outline)
    for (const word of lang.defineSuffix) {
      this.children.push(new Label(word))
    }
    return
  }

  var type = blocksById[id]
  var oldSpec = this.info.language.commands[type.spec]

  var nativeSpec = lang.commands[type.spec]
  if (!nativeSpec) return
  var nativeInfo = parseSpec(nativeSpec)

  var rawArgs = this.children.filter(function(child) {
    return !child.isLabel && !child.isIcon
  })

  if (!isShallow) {
    rawArgs.forEach(function(child) {
      child.translate(lang)
    })
  }

  // Work out indexes of existing children
  var oldParts = parseSpec(oldSpec).parts
  var oldInputOrder = oldParts
    .map(part => parseInputNumber(part))
    .filter(x => !!x)

  var highestNumber = 0
  var args = oldInputOrder.map(number => {
    highestNumber = Math.max(highestNumber, number)
    return rawArgs[number - 1]
  })
  var remainingArgs = rawArgs.slice(highestNumber)

  // Get new children by index
  this.children = nativeInfo.parts
    .map(function(part) {
      var part = part.trim()
      if (!part) return
      var number = parseInputNumber(part)
      if (number) {
        return args[number - 1]
      } else {
        return iconPat.test(part) ? new Icon(part.slice(1)) : new Label(part)
      }
    })
    .filter(x => !!x)

  // Push any remaining children, so we pick up C block bodies
  remainingArgs.forEach((arg, index) => {
    if (index === 1 && this.info.id === "CONTROL_IF") {
      this.children.push(new Label(lang.commands["else"]))
    }
    this.children.push(arg)
  })

  this.info.language = lang
  this.info.isRTL = rtlLanguages.indexOf(lang.code) > -1
  this.info.categoryIsDefault = true
}

/* Comment */

var Comment = function(value, hasBlock) {
  this.label = new Label(value, "comment-label")
  this.width = null
  this.hasBlock = hasBlock
}
Comment.prototype.isComment = true

Comment.prototype.stringify = function() {
  return "// " + this.label.value
}

/* Glow */

var Glow = function(child) {
  assert(child)
  this.child = child
  if (child.isBlock) {
    this.shape = child.info.shape
    this.info = child.info
  } else {
    this.shape = "stack"
  }
}
Glow.prototype.isGlow = true

Glow.prototype.stringify = function() {
  if (this.child.isBlock) {
    return this.child.stringify("+")
  } else {
    var lines = this.child.stringify().split("\n")
    return lines.map(line => "+ " + line).join("\n")
  }
}

Glow.prototype.translate = function(lang) {
  this.child.translate(lang)
}

/* Script */

var Script = function(blocks) {
  this.blocks = blocks
  this.isEmpty = !blocks.length
  this.isFinal = !this.isEmpty && blocks[blocks.length - 1].isFinal
}
Script.prototype.isScript = true

Script.prototype.stringify = function() {
  return this.blocks
    .map(function(block) {
      var line = block.stringify()
      if (block.comment) line += " " + block.comment.stringify()
      return line
    })
    .join("\n")
}

Script.prototype.translate = function(lang) {
  this.blocks.forEach(function(block) {
    block.translate(lang)
  })
}

/* Document */

var Document = function(scripts) {
  this.scripts = scripts
}

Document.prototype.stringify = function() {
  return this.scripts
    .map(function(script) {
      return script.stringify()
    })
    .join("\n\n")
}

Document.prototype.translate = function(lang) {
  this.scripts.forEach(function(script) {
    script.translate(lang)
  })
}

module.exports = {
  Label,
  Icon,
  Input,
  Block,
  Comment,
  Glow,
  Script,
  Document,
}
<commit_msg>Don't crop puzzle piece from trailing C blocks<commit_after>function assert(bool, message) {
  if (!bool) throw "Assertion failed! " + (message || "")
}
function isArray(o) {
  return o && o.constructor === Array
}

function indent(text) {
  return text
    .split("\n")
    .map(function(line) {
      return "  " + line
    })
    .join("\n")
}

function maybeNumber(v) {
  v = "" + v
  var n = parseInt(v)
  if (!isNaN(n)) {
    return n
  }
  var f = parseFloat(v)
  if (!isNaN(f)) {
    return f
  }
  return v
}

var {
  blocksById,
  parseSpec,
  inputPat,
  parseInputNumber,
  iconPat,
  rtlLanguages,
  unicodeIcons,
  english,
  blockName,
} = require("./blocks.js")

/* Label */

var Label = function(value, cls) {
  this.value = value
  this.cls = cls || ""
  this.el = null
  this.height = 12
  this.metrics = null
  this.x = 0
}
Label.prototype.isLabel = true

Label.prototype.stringify = function() {
  if (this.value === "<" || this.value === ">") return this.value
  return this.value.replace(/([<>[\](){}])/g, "\\$1")
}

/* Icon */

var Icon = function(name) {
  this.name = name
  this.isArrow = name === "loopArrow"

  assert(Icon.icons[name], "no info for icon " + name)
}
Icon.prototype.isIcon = true

Icon.icons = {
  greenFlag: true,
  turnLeft: true,
  turnRight: true,
  loopArrow: true,
  addInput: true,
  delInput: true,
}

Icon.prototype.stringify = function() {
  return unicodeIcons["@" + this.name] || ""
}

/* Input */

var Input = function(shape, value, menu) {
  this.shape = shape
  this.value = value
  this.menu = menu || null

  this.isRound = shape === "number" || shape === "number-dropdown"
  this.isBoolean = shape === "boolean"
  this.isStack = shape === "stack"
  this.isInset =
    shape === "boolean" || shape === "stack" || shape === "reporter"
  this.isColor = shape === "color"
  this.hasArrow = shape === "dropdown" || shape === "number-dropdown"
  this.isDarker =
    shape === "boolean" || shape === "stack" || shape === "dropdown"
  this.isSquare =
    shape === "string" || shape === "color" || shape === "dropdown"

  this.hasLabel = !(this.isColor || this.isInset)
  this.label = this.hasLabel ? new Label(value, "literal-" + this.shape) : null
  this.x = 0
}
Input.prototype.isInput = true

Input.prototype.stringify = function() {
  if (this.isColor) {
    assert(this.value[0] === "#")
    return "[" + this.value + "]"
  }
  var text = (this.value ? "" + this.value : "")
    .replace(/ v$/, " \\v")
    .replace(/([\]\\])/g, "\\$1")
  if (this.hasArrow) text += " v"
  return this.isRound
    ? "(" + text + ")"
    : this.isSquare
      ? "[" + text + "]"
      : this.isBoolean ? "<>" : this.isStack ? "{}" : text
}

Input.prototype.translate = function(lang) {
  if (this.hasArrow) {
    var value = this.menu || this.value
    this.value = value // TODO translate dropdown value
    this.label = new Label(this.value, "literal-" + this.shape)
  }
}

/* Block */

var Block = function(info, children, comment) {
  assert(info)
  this.info = Object.assign({}, info)
  this.children = children
  this.comment = comment || null
  this.diff = null

  var shape = this.info.shape
  this.isHat = shape === "hat" || shape === "cat" || shape === "define-hat"
  this.hasPuzzle = shape === "stack" || shape === "hat" || shape === "cat" || shape === "c-block"
  this.isFinal = /cap/.test(shape)
  this.isCommand = shape === "stack" || shape === "cap" || /block/.test(shape)
  this.isOutline = shape === "outline"
  this.isReporter = shape === "reporter"
  this.isBoolean = shape === "boolean"

  this.isRing = shape === "ring"
  this.hasScript = /block/.test(shape)
  this.isElse = shape === "celse"
  this.isEnd = shape === "cend"
}
Block.prototype.isBlock = true

Block.prototype.stringify = function(extras) {
  var firstInput = null
  var checkAlias = false
  var text = this.children
    .map(function(child) {
      if (child.isIcon) checkAlias = true
      if (!firstInput && !(child.isLabel || child.isIcon)) firstInput = child
      return child.isScript
        ? "\n" + indent(child.stringify()) + "\n"
        : child.stringify().trim() + " "
    })
    .join("")
    .trim()

  var lang = this.info.language
  if (checkAlias && lang && this.info.selector) {
    var type = blocksById[this.info.id]
    var spec = type.spec
    var alias = lang.nativeAliases[type.spec]
    if (alias) {
      // TODO make translate() not in-place, and use that
      if (inputPat.test(alias) && firstInput) {
        alias = alias.replace(inputPat, firstInput.stringify())
      }
      return alias
    }
  }

  var overrides = extras || ""
  if (
    this.info.categoryIsDefault === false ||
    (this.info.category === "custom-arg" &&
      (this.isReporter || this.isBoolean)) ||
    (this.info.category === "custom" && this.info.shape === "stack")
  ) {
    if (overrides) overrides += " "
    overrides += this.info.category
  }
  if (overrides) {
    text += " :: " + overrides
  }
  return this.hasScript
    ? text + "\nend"
    : this.info.shape === "reporter"
      ? "(" + text + ")"
      : this.info.shape === "boolean" ? "<" + text + ">" : text
}

Block.prototype.translate = function(lang, isShallow) {
  if (!lang) throw new Error("Missing language")

  var id = this.info.id
  if (!id) return

  if (id === "PROCEDURES_DEFINITION") {
    // Find the first 'outline' child (there should be exactly one).
    const outline = this.children.find(child => child.isOutline)

    this.children = []
    for (const word of lang.definePrefix) {
      this.children.push(new Label(word))
    }
    this.children.push(outline)
    for (const word of lang.defineSuffix) {
      this.children.push(new Label(word))
    }
    return
  }

  var type = blocksById[id]
  var oldSpec = this.info.language.commands[type.spec]

  var nativeSpec = lang.commands[type.spec]
  if (!nativeSpec) return
  var nativeInfo = parseSpec(nativeSpec)

  var rawArgs = this.children.filter(function(child) {
    return !child.isLabel && !child.isIcon
  })

  if (!isShallow) {
    rawArgs.forEach(function(child) {
      child.translate(lang)
    })
  }

  // Work out indexes of existing children
  var oldParts = parseSpec(oldSpec).parts
  var oldInputOrder = oldParts
    .map(part => parseInputNumber(part))
    .filter(x => !!x)

  var highestNumber = 0
  var args = oldInputOrder.map(number => {
    highestNumber = Math.max(highestNumber, number)
    return rawArgs[number - 1]
  })
  var remainingArgs = rawArgs.slice(highestNumber)

  // Get new children by index
  this.children = nativeInfo.parts
    .map(function(part) {
      var part = part.trim()
      if (!part) return
      var number = parseInputNumber(part)
      if (number) {
        return args[number - 1]
      } else {
        return iconPat.test(part) ? new Icon(part.slice(1)) : new Label(part)
      }
    })
    .filter(x => !!x)

  // Push any remaining children, so we pick up C block bodies
  remainingArgs.forEach((arg, index) => {
    if (index === 1 && this.info.id === "CONTROL_IF") {
      this.children.push(new Label(lang.commands["else"]))
    }
    this.children.push(arg)
  })

  this.info.language = lang
  this.info.isRTL = rtlLanguages.indexOf(lang.code) > -1
  this.info.categoryIsDefault = true
}

/* Comment */

var Comment = function(value, hasBlock) {
  this.label = new Label(value, "comment-label")
  this.width = null
  this.hasBlock = hasBlock
}
Comment.prototype.isComment = true

Comment.prototype.stringify = function() {
  return "// " + this.label.value
}

/* Glow */

var Glow = function(child) {
  assert(child)
  this.child = child
  if (child.isBlock) {
    this.shape = child.info.shape
    this.info = child.info
  } else {
    this.shape = "stack"
  }
}
Glow.prototype.isGlow = true

Glow.prototype.stringify = function() {
  if (this.child.isBlock) {
    return this.child.stringify("+")
  } else {
    var lines = this.child.stringify().split("\n")
    return lines.map(line => "+ " + line).join("\n")
  }
}

Glow.prototype.translate = function(lang) {
  this.child.translate(lang)
}

/* Script */

var Script = function(blocks) {
  this.blocks = blocks
  this.isEmpty = !blocks.length
  this.isFinal = !this.isEmpty && blocks[blocks.length - 1].isFinal
}
Script.prototype.isScript = true

Script.prototype.stringify = function() {
  return this.blocks
    .map(function(block) {
      var line = block.stringify()
      if (block.comment) line += " " + block.comment.stringify()
      return line
    })
    .join("\n")
}

Script.prototype.translate = function(lang) {
  this.blocks.forEach(function(block) {
    block.translate(lang)
  })
}

/* Document */

var Document = function(scripts) {
  this.scripts = scripts
}

Document.prototype.stringify = function() {
  return this.scripts
    .map(function(script) {
      return script.stringify()
    })
    .join("\n\n")
}

Document.prototype.translate = function(lang) {
  this.scripts.forEach(function(script) {
    script.translate(lang)
  })
}

module.exports = {
  Label,
  Icon,
  Input,
  Block,
  Comment,
  Glow,
  Script,
  Document,
}
<|endoftext|>


<commit_before>import Inferno from 'inferno'
import Component from 'inferno-component'
import { Link } from 'inferno-router'

export default class Docs extends Component {
    constructor(props) {
        super(props)
        this.state = {
            markdown: null,
            prevURL: null
        }
    }

    componentWillReceiveProps({ params }) {
        this.loadDocument(params.path)
    }

    componentDidMount() {
        const { params } = this.props
		this.loadDocument(params.path || '/docs/guides/get-started.md')
    }

	loadDocument = (to, changeRoute) => {
        const { router } = this.context
        const path = '/' + to.replace('/docs/', '')

        if (changeRoute) {
            return router.push(to)
        }

        fetch(`/api/markdown?file=${path}`)
        .then(response => response.json())
        .then(response => {
            this.setState({ markdown: response })
        })
	}

    render() {
        const MenuLink = ({ to, children }) => {
            return

                <Link activeClassName="selected" to={to}>
                    {children}
                </Link>

        }
        return

Guides

                    <MenuLink to={'/docs/guides/installation.md'}>Installation</MenuLink>
                    <MenuLink to={'/docs/guides/getting-started.md'}>Getting Started</MenuLink>
                    <MenuLink to={'/docs/guides/what-is-jsx.md'}>What is JSX?</MenuLink>
                    <MenuLink to={'/docs/guides/project-layout.md'}>Project Layout</MenuLink>
                    <MenuLink to={'/docs/guides/event-handling.md'}>Event Handling</MenuLink>
                    <MenuLink to={'/docs/guides/form-input.md'}>Form Input</MenuLink>
                    <MenuLink to={'/docs/guides/creating-components.md'}>Components</MenuLink>

Advanced

                    <MenuLink to={'/docs/guides/what-is-virtual-dom.md'}>What is Virtual DOM?</MenuLink>
                    <MenuLink to={'/docs/guides/alternatives-to-jsx.md'}>Alternatives to JSX</MenuLink>
                    <MenuLink to={'/docs/guides/devtools.md'}>Dev Tools</MenuLink>
                    <MenuLink to={'/docs/guides/state.md'}>State</MenuLink>
                    <MenuLink to={'/docs/guides/routing.md'}>Routing</MenuLink>
                    <MenuLink to={'/docs/guides/server-side-rendering.md'}>Server-side rendering</MenuLink>
                    <MenuLink to={'/docs/guides/testing.md'}>Testing</MenuLink>
                    <MenuLink to={'/docs/guides/typescriot-support.md'}>TypeScript Support</MenuLink>

Meta

                    <MenuLink to={'/docs/guides/comparisons-with-other-frameworks.md'}>Comparisons with Other Frameworks</MenuLink>
                    <MenuLink to={'https://inferno-slack.herokuapp.com/'}>Join the Inferno Community</MenuLink>

API

                    <MenuLink to={'/docs/api/inferno.md'}>Inferno</MenuLink>
                    <MenuLink to={'/docs/api/inferno-compat.md'}>Inferno-compat</MenuLink>
                    <MenuLink to={'/docs/api/inferno-component.md'}>Inferno-component</MenuLink>
                    <MenuLink to={'/docs/api/inferno-create-class.md'}>Inferno-create-class</MenuLink>
                    <MenuLink to={'/docs/api/inferno-create-element.md'}>Inferno-create-element</MenuLink>
                    <MenuLink to={'/docs/api/inferno-hyperscript.md'}>Inferno-hyperscript</MenuLink>
                    <MenuLink to={'/docs/api/inferno-component.md'}>Inferno-devtools</MenuLink>
                    <MenuLink to={'/docs/api/inferno-mobx.md'}>Inferno-mobx</MenuLink>
                    <MenuLink to={'/docs/api/inferno-redux.md'}>Inferno-redux</MenuLink>
                    <MenuLink to={'/docs/api/inferno-router.md'}>Inferno-router</MenuLink>
                    <MenuLink to={'/docs/api/inferno-server.md'}>Inferno-server</MenuLink>
                    <MenuLink to={'/docs/api/inferno-test-utils.md'}>Inferno-test-utils</MenuLink>
                    <MenuLink to={'/docs/api/inferno-test-utils.md'}>Inferno-vnode-flags</MenuLink>

				{this.state.markdown}

    }
}

/*
let markdown = ''

function onComponentDidMount() {
	fetch('/api/markdown?file=guides/installation.md')
	.then(response => response.json())
	.then(response => {
		markdown = response
	})
}

function DocsContent() {
	if (process.env.BROWSER) {
		document.title = 'About'
	}
	return
		<DocsContent onComponentDidMount={onComponentDidMount}/>

}

export default function Docs() {
	if (process.env.BROWSER) {
		document.title = 'About'
	}
	return
		<DocsContent/>

}*/

function toArray(arr) {
    return Array.isArray(arr) ? arr : [arr]
}

/*
    render() {
        return

                <Link to="/docs/guides/overview.md">Overview</Link>
                <Link to="/docs/guides/installation.md">Installation</Link>

    }
* */
<commit_msg>updated default path<commit_after>import Inferno from 'inferno'
import Component from 'inferno-component'
import { Link } from 'inferno-router'

export default class Docs extends Component {
    constructor(props) {
        super(props)
        this.state = {
            markdown: null,
            prevURL: null
        }
    }

    componentWillReceiveProps({ params }) {
        this.loadDocument(params.path)
    }

    componentDidMount() {
        const { params } = this.props
		this.loadDocument(params.path || '/docs/guides/installation.md')
    }

	loadDocument = (to, changeRoute) => {
        const { router } = this.context
        const path = '/' + to.replace('/docs/', '')

        if (changeRoute) {
            return router.push(to)
        }

        fetch(`/api/markdown?file=${path}`)
        .then(response => response.json())
        .then(response => {
            this.setState({ markdown: response })
        })
	}

    render() {
        const MenuLink = ({ to, children }) => {
            return

                <Link activeClassName="selected" to={to}>
                    {children}
                </Link>

        }
        return

Guides

                    <MenuLink to={'/docs/guides/installation.md'}>Installation</MenuLink>
                    <MenuLink to={'/docs/guides/getting-started.md'}>Getting Started</MenuLink>
                    <MenuLink to={'/docs/guides/what-is-jsx.md'}>What is JSX?</MenuLink>
                    <MenuLink to={'/docs/guides/project-layout.md'}>Project Layout</MenuLink>
                    <MenuLink to={'/docs/guides/event-handling.md'}>Event Handling</MenuLink>
                    <MenuLink to={'/docs/guides/form-input.md'}>Form Input</MenuLink>
                    <MenuLink to={'/docs/guides/creating-components.md'}>Components</MenuLink>

Advanced

                    <MenuLink to={'/docs/guides/what-is-virtual-dom.md'}>What is Virtual DOM?</MenuLink>
                    <MenuLink to={'/docs/guides/alternatives-to-jsx.md'}>Alternatives to JSX</MenuLink>
                    <MenuLink to={'/docs/guides/devtools.md'}>Dev Tools</MenuLink>
                    <MenuLink to={'/docs/guides/state.md'}>State</MenuLink>
                    <MenuLink to={'/docs/guides/routing.md'}>Routing</MenuLink>
                    <MenuLink to={'/docs/guides/server-side-rendering.md'}>Server-side rendering</MenuLink>
                    <MenuLink to={'/docs/guides/testing.md'}>Testing</MenuLink>
                    <MenuLink to={'/docs/guides/typescriot-support.md'}>TypeScript Support</MenuLink>

Meta

                    <MenuLink to={'/docs/guides/comparisons-with-other-frameworks.md'}>Comparisons with Other Frameworks</MenuLink>
                    <MenuLink to={'https://inferno-slack.herokuapp.com/'}>Join the Inferno Community</MenuLink>

API

                    <MenuLink to={'/docs/api/inferno.md'}>Inferno</MenuLink>
                    <MenuLink to={'/docs/api/inferno-compat.md'}>Inferno-compat</MenuLink>
                    <MenuLink to={'/docs/api/inferno-component.md'}>Inferno-component</MenuLink>
                    <MenuLink to={'/docs/api/inferno-create-class.md'}>Inferno-create-class</MenuLink>
                    <MenuLink to={'/docs/api/inferno-create-element.md'}>Inferno-create-element</MenuLink>
                    <MenuLink to={'/docs/api/inferno-hyperscript.md'}>Inferno-hyperscript</MenuLink>
                    <MenuLink to={'/docs/api/inferno-component.md'}>Inferno-devtools</MenuLink>
                    <MenuLink to={'/docs/api/inferno-mobx.md'}>Inferno-mobx</MenuLink>
                    <MenuLink to={'/docs/api/inferno-redux.md'}>Inferno-redux</MenuLink>
                    <MenuLink to={'/docs/api/inferno-router.md'}>Inferno-router</MenuLink>
                    <MenuLink to={'/docs/api/inferno-server.md'}>Inferno-server</MenuLink>
                    <MenuLink to={'/docs/api/inferno-test-utils.md'}>Inferno-test-utils</MenuLink>
                    <MenuLink to={'/docs/api/inferno-test-utils.md'}>Inferno-vnode-flags</MenuLink>

				{this.state.markdown}

    }
}

/*
let markdown = ''

function onComponentDidMount() {
	fetch('/api/markdown?file=guides/installation.md')
	.then(response => response.json())
	.then(response => {
		markdown = response
	})
}

function DocsContent() {
	if (process.env.BROWSER) {
		document.title = 'About'
	}
	return
		<DocsContent onComponentDidMount={onComponentDidMount}/>

}

export default function Docs() {
	if (process.env.BROWSER) {
		document.title = 'About'
	}
	return
		<DocsContent/>

}*/

function toArray(arr) {
    return Array.isArray(arr) ? arr : [arr]
}

/*
    render() {
        return

                <Link to="/docs/guides/overview.md">Overview</Link>
                <Link to="/docs/guides/installation.md">Installation</Link>

    }
* */
<|endoftext|>