<commit_before>'use strict';

var   byline     = require("byline"),
      fs         = require("fs"),
      Polygon    = require (__dirname + "/elements/polygon"),
      Circle     = require (__dirname + "/elements/circle"),
      Text       = require (__dirname + "/elements/text"),
      Point      = require (__dirname + "/elements/point");

var Parser = {};

/**
 * Transform a dxf file into an array where keys are the names of dxf sections
 * @param {String}     dxfPath     "path/of/dxf/file"
 * @param {Function}   callback    Callback function
 */
Parser.toArray = function (dxfPath, callback) {

    var stream         = byline(fs.createReadStream(dxfPath, { encoding: 'utf8' })),
        sectionNameTab = ['HEADER', 'CLASSES', 'TABLES', 'BLOCKS', 'ENTITIES', 'OBJECTS', 'THUMBNAILIMAGE'],
        sectionCur     = '',
        dxfTab         = [],
        section        = false,
        endsec         = false;

    stream.on('data', function (line) {
        if (sectionNameTab.indexOf(line) != -1) {
            sectionCur = line.toLowerCase();
            section = true;
            dxfTab[sectionCur] = [];
            endsec = false;
        }
        else if (section === true) {
            if (line === 'ENDSEC') {
                endsec = true;
                section = false;
                sectionCur = '';
            }
            else if (endsec === false) {
                dxfTab[sectionCur].push(line);
            }
        }
    });
    stream.on('error', function (error) {
        callback(error);
    });
    stream.on('end', function () {
        callback(null, dxfTab);
    });
};

/**
 * Get the polygons in the DXF file
 * @param   {Array}   sectionTab      Polygons are in the entities section
 * @returns {Array}   polygons        An array of polygons
 */
Parser.getPolygons = function (sectionTab) {

    var polygons    = [],
        polygon     = undefined,
        sectionTab  = sectionTab.entities,
        polygonBool = false;

    sectionTab.forEach(function (line, li) {
        if (line === 'LWPOLYLINE') {
            polygonBool = true;
            polygon     = new Polygon();
        }
        else if (polygonBool === true && line === '  8') polygon.setLayer(sectionTab[li + 1]);
        else if (polygonBool === true && line === ' 90') polygon.setNumberPoints(parseInt(sectionTab[li + 1]));
        else if (polygonBool === true && line === ' 10') {
            var point = new Point();
            point.setX(parseFloat(sectionTab[li + 1]));
            point.setY(parseFloat(sectionTab[li + 3]));
            if (sectionTab[li + 4] === ' 42') point.setBulge(parseFloat(sectionTab[li + 5]));
            polygon.addPoint(point);
        }
        else if (
            polygonBool === true &&
            polygon.numberPoints !== 0 &&
            polygon.layer !== 'defaultLayer' &&
            polygon.points.length === polygon.numberPoints
        ){
            polygonBool = false;
            if(!polygons[polygon.layer]) polygons[polygon.layer] = [polygon];
            else polygons[polygon.layer].push(polygon);
        }
    });
    return polygons;
};

/**
 * Get the circles in the DXF file
 * @param   {Array}     sectionTab          Circles are in the entities section
 * @param   {object}    options             Function options
 * @param   {boolean}   options.toPolygon   true if you want to transforrm directly the circles into polygons
 * @param   {int}       options.nbSides     you can choose the number of sides of polygons from circle (default 20 sides)
 * @returns {Array}     circles             An array of circles
 */
Parser.getCircles = function (sectionTab, options){

    var circles             = [],
        polygonFromCircle   = undefined,
        circle              = undefined,
        sectionTab          = sectionTab.entities,
        toPolygon           = options !== undefined ? options.toPolygon : false,
        nbSides             = options !== undefined ? options.nbSides : 20,
        circleBool          = false;

    sectionTab.forEach(function (line, li){
        if(line === 'CIRCLE'){
            circleBool = true;
            circle = new Circle();
        }
        else if(circleBool === true && line === '  8') circle.setLayer(sectionTab[li+1]);
        else if(circleBool === true && line === ' 10') {
            var point = new Point();
            point.setX(parseFloat(sectionTab[li + 1]));
            point.setY(parseFloat(sectionTab[li + 3]));
            circle.setPoint(point);
        }
        else if(circleBool === true && line === ' 40') circle.setRayon(sectionTab[li+1]);
        else if(
            circleBool === true &&
            circle.layer !== 'defaultLayer' &&
            circle.point !== undefined &&
            circle.rayon !== 0
        ){
            circleBool = false;
            if (toPolygon){
                polygonFromCircle = circle.toPolygon(nbSides);
                if(!circles[polygonFromCircle.layer]) circles[polygonFromCircle.layer] = [polygonFromCircle];
                else circles[polygonFromCircle.layer].push(polygonFromCircle);
            }
            else{
                if(!circles[circle.layer]) circles[circle.layer] = [circle];
                else circles[circle.layer].push(circle);
            }
        }
    });
    return circles;
};

/**
 * Get the texts in the DXF file
 * @param   {Array}    sectionTab         The texts are in the entities section
 * @returns {Array}    texts              An array of texts
 */
Parser.getTexts = function (sectionTab){

    var texts         = [],
        text          = undefined,
        sectionTab    = sectionTab.entities,
        textBool      = false;

    sectionTab.forEach(function (line, li){
        if(line == 'TEXT' || line == 'MTEXT'){
            textBool = true;
            text = new Text();
        }
        else if(textBool == true && line == '  8') text.setLayer(sectionTab[li+1]);
        else if(textBool == true && line == ' 10') {
            var point = new Point();
            point.setX(parseFloat(sectionTab[li + 1]));
            point.setY(parseFloat(sectionTab[li + 3]));
            text.setPoint(point);
        }
        else if(textBool == true && line == '  1') {
            text.setContents(sectionTab[li+1]);
            text.contentsParse();
        }
        else if(
            textBool == true &&
            text.layer != 'defaultLayer' &&
            text.contents != 'defaultContents' &&
            text.point != undefined

        ){
            textBool = false;
            if(text.contents !== ''){
                if(!texts[text.layer]) texts[text.layer] = [text];
                else texts[text.layer].push(text);
            }
        }
    });
    return texts;
};

/**
 * Get Parameters : the origin point of the view, its center point and its rotate angle
 * @param   {Array}    sectionTab     The parameters are in the tables section
 * @returns {Object}   params         originPoint, viewCenterPoint, rotateAngle
 */
Parser.getParameters = function (sectionTab) {

    var params     = {originPoint: undefined, viewCenterPoint: undefined, rotateAngle: undefined},
        sectionTab = sectionTab.tables,
        vPort      = false;

    sectionTab.forEach(function (line, li) {
        if (line == 'AcDbViewportTableRecord') vPort = true;

        else if (vPort == true && line == ' 12'){
            var viewCenterPoint = new Point();
            viewCenterPoint.setX(parseFloat(sectionTab[li + 1]));
            viewCenterPoint.setY(parseFloat(sectionTab[li + 3]));
            params.viewCenterPoint = viewCenterPoint;
        }
        else if (vPort == true && line == ' 13'){
            var originPoint = new Point();
            originPoint.setX(parseFloat(sectionTab[li + 1]));
            originPoint.setY(parseFloat(sectionTab[li + 3]));
            params.originPoint = originPoint;
        }
        else if (vPort == true && line == ' 51') params.rotateAngle = parseFloat(sectionTab[li + 1]);
        else if (
            vPort == true && params.rotateAngle != undefined &&
            params.originPoint != undefined &&
            params.viewCenterPoint != undefined)
        {
            vPort = false;
        }
    });
    return params;
};

/**
 * Get the layers of the appropriate entities in the DXF file
 * @param    {Array}    sectionTab     The specific layers are in the entities section
 * @param    {Array}    tabEnt         You can put "text","polygon" or "circle" in the tabEnt (all by default)
 * @returns  {Array}    layers
 */
Parser.getLayersByEntities = function (sectionTab, tabEnt){

    var layers     = [],
        tabTmp     = tabEnt || 'all',
        ent        = false;

    if(tabTmp === 'all') layers = Parser.getAllLayers(sectionTab);
    else{
        var sectionTab = sectionTab.entities,
            tabEnt     = [];

        if (tabTmp.indexOf("text") !== -1) tabEnt.push("MTEXT", "TEXT");
        if (tabTmp.indexOf("polygon") !== -1) tabEnt.push("LWPOLYLINE");
        if (tabTmp.indexOf("circle") !== -1) tabEnt.push("CIRCLE");

        sectionTab.forEach(function (line, li){
            if(tabEnt.indexOf(line) !== -1) ent = true;
            else if(ent === true && line == '  8'){
                if(layers.indexOf(sectionTab[li+1].replace(/ {1,}/g,"")) === -1) layers.push(sectionTab[li+1].replace(/ {1,}/g,""));
            }
        });
    }
    return layers;
};

/**
 * Get all layers of the DXF file
 * @param   {Array}    sectionTab     All layers are in the tables section
 * @returns {Array}    layer
 */
Parser.getAllLayers = function (sectionTab){

    var layers       = [],
        sectionTab   = sectionTab.tables,
        getLayer     = false;

    sectionTab.forEach(function (line, li){
        if(line === "AcDbLayerTableRecord") getLayer = true;
        else if(getLayer === true && line === '  2'){
            if(layers.indexOf(sectionTab[li+1].replace(/ {1,}/g,"")) === -1){
                layers.push(sectionTab[li+1].replace(/ {1,}/g,""));
                getLayer = false;
            }
        }
    });
    return layers;
};

/**
 * Established a mapping between polygons and texts
 * @param    {object}    polygons
 * @param    {object}    texts
 * @returns  {Array}     mapping
 */
Parser.makeMappings = function (polygons, texts){

    var mappings = [];

    texts.forEach(function (text){
        polygons.forEach(function (polygon, p){
            if(polygon.points !== undefined){
                if(text.point.isInside(polygon.points)){
                    if(!mappings[p]) mappings[p] = {polygon : polygon, texts : [text]};
                    else mappings[p].texts.push(text);
                }
            }
        });
    });
    return mappings;
};

/**
 * Get the polygons of the DXF file which does not have text
 * @param   {Array}  polygons
 * @param   {Array}  texts
 * @returns {Array}  polygonWithoutText
 */
Parser.getPolygonsWithoutText = function (polygons, texts){

    var polygonWithoutText = [];

    polygons.forEach(function(polygon){

        var textInPolygon = [];

        texts.forEach(function (text, t){
            if(polygon.points !== undefined){
                if(text.point.isInside(polygon.points)) textInPolygon.push(t);
            }
        });
        if (textInPolygon.length === 0) polygonWithoutText.push(polygon);
    });
    return polygonWithoutText;
};

/**
 * Get the Texts of the DXF file which does not have polygon
 * @param   {Array}  texts
 * @param   {Array}  polygons
 * @returns {Array}  textsWithoutPolygon
 */
Parser.getTextsWithoutPolygon = function (texts, polygons){

    var textsWithoutPolygon = [];

    texts.forEach(function(text){

        var polygonWithText = [];

        polygons.forEach(function (polygon, p){
            if(polygon.points !== undefined){
                if(text.point.isInside(polygon.points)) polygonWithText.push(p);
            }
        });
        if (polygonWithText.length === 0) textsWithoutPolygon.push(text);
    });
    return textsWithoutPolygon;
};

/**
 * Return the min x,z  and the max x,y of the polygon's array
 * @param   {Array}     polygons
 * @returns {Object}    {min: point, max: point}
 */
Parser.getDimensions = function (polygons){

    var minPoint = new Point(),
        maxPoint = new Point();

    polygons.forEach(function (polygon, p) {
        polygon.points.forEach(function (tpoint, i) {
            minPoint.x = tpoint.x < minPoint.x ? tpoint.x : (i === 0 && p === 0 ? tpoint.x : minPoint.x);
            minPoint.y = tpoint.y < minPoint.y ? tpoint.y : (i === 0 && p === 0 ? tpoint.y : minPoint.y);
            maxPoint.x = tpoint.x > maxPoint.x ? tpoint.x : (i === 0 && p === 0 ? tpoint.x : maxPoint.x);
            maxPoint.y = tpoint.y > maxPoint.y ? tpoint.y : (i === 0 && p === 0 ? tpoint.y : maxPoint.y);
        });
    });
    return {
        'min': minPoint,
        'max': maxPoint
    }
};

module.exports = Parser;
<commit_msg>escape " "<commit_after>'use strict';

var   byline     = require("byline"),
      fs         = require("fs"),
      Polygon    = require (__dirname + "/elements/polygon"),
      Circle     = require (__dirname + "/elements/circle"),
      Text       = require (__dirname + "/elements/text"),
      Point      = require (__dirname + "/elements/point");

var Parser = {};

/**
 * Transform a dxf file into an array where keys are the names of dxf sections
 * @param {String}     dxfPath     "path/of/dxf/file"
 * @param {Function}   callback    Callback function
 */
Parser.toArray = function (dxfPath, callback) {

    var stream         = byline(fs.createReadStream(dxfPath, { encoding: 'utf8' })),
        sectionNameTab = ['HEADER', 'CLASSES', 'TABLES', 'BLOCKS', 'ENTITIES', 'OBJECTS', 'THUMBNAILIMAGE'],
        sectionCur     = '',
        dxfTab         = [],
        section        = false,
        endsec         = false;

    stream.on('data', function (line) {
        if (sectionNameTab.indexOf(line) != -1) {
            sectionCur = line.toLowerCase();
            section = true;
            dxfTab[sectionCur] = [];
            endsec = false;
        }
        else if (section === true) {
            if (line === 'ENDSEC') {
                endsec = true;
                section = false;
                sectionCur = '';
            }
            else if (endsec === false) {
                dxfTab[sectionCur].push(line);
            }
        }
    });
    stream.on('error', function (error) {
        callback(error);
    });
    stream.on('end', function () {
        callback(null, dxfTab);
    });
};

/**
 * Get the polygons in the DXF file
 * @param   {Array}   sectionTab      Polygons are in the entities section
 * @returns {Array}   polygons        An array of polygons
 */
Parser.getPolygons = function (sectionTab) {

    var polygons    = [],
        polygon     = undefined,
        sectionTab  = sectionTab.entities,
        polygonBool = false;

    sectionTab.forEach(function (line, li) {
        if (line === 'LWPOLYLINE') {
            polygonBool = true;
            polygon     = new Polygon();
        }
        else if (polygonBool === true && line === '  8') polygon.setLayer(sectionTab[li + 1]);
        else if (polygonBool === true && line === ' 90') polygon.setNumberPoints(parseInt(sectionTab[li + 1]));
        else if (polygonBool === true && line === ' 10') {
            var point = new Point();
            point.setX(parseFloat(sectionTab[li + 1]));
            point.setY(parseFloat(sectionTab[li + 3]));
            if (sectionTab[li + 4] === ' 42') point.setBulge(parseFloat(sectionTab[li + 5]));
            polygon.addPoint(point);
        }
        else if (
            polygonBool === true &&
            polygon.numberPoints !== 0 &&
            polygon.layer !== 'defaultLayer' &&
            polygon.points.length === polygon.numberPoints
        ){
            polygonBool = false;
            if(!polygons[polygon.layer]) polygons[polygon.layer] = [polygon];
            else polygons[polygon.layer].push(polygon);
        }
    });
    return polygons;
};

/**
 * Get the circles in the DXF file
 * @param   {Array}     sectionTab          Circles are in the entities section
 * @param   {object}    options             Function options
 * @param   {boolean}   options.toPolygon   true if you want to transforrm directly the circles into polygons
 * @param   {int}       options.nbSides     you can choose the number of sides of polygons from circle (default 20 sides)
 * @returns {Array}     circles             An array of circles
 */
Parser.getCircles = function (sectionTab, options){

    var circles             = [],
        polygonFromCircle   = undefined,
        circle              = undefined,
        sectionTab          = sectionTab.entities,
        toPolygon           = options !== undefined ? options.toPolygon : false,
        nbSides             = options !== undefined ? options.nbSides : 20,
        circleBool          = false;

    sectionTab.forEach(function (line, li){
        if(line === 'CIRCLE'){
            circleBool = true;
            circle = new Circle();
        }
        else if(circleBool === true && line === '  8') circle.setLayer(sectionTab[li+1]);
        else if(circleBool === true && line === ' 10') {
            var point = new Point();
            point.setX(parseFloat(sectionTab[li + 1]));
            point.setY(parseFloat(sectionTab[li + 3]));
            circle.setPoint(point);
        }
        else if(circleBool === true && line === ' 40') circle.setRayon(sectionTab[li+1]);
        else if(
            circleBool === true &&
            circle.layer !== 'defaultLayer' &&
            circle.point !== undefined &&
            circle.rayon !== 0
        ){
            circleBool = false;
            if (toPolygon){
                polygonFromCircle = circle.toPolygon(nbSides);
                if(!circles[polygonFromCircle.layer]) circles[polygonFromCircle.layer] = [polygonFromCircle];
                else circles[polygonFromCircle.layer].push(polygonFromCircle);
            }
            else{
                if(!circles[circle.layer]) circles[circle.layer] = [circle];
                else circles[circle.layer].push(circle);
            }
        }
    });
    return circles;
};

/**
 * Get the texts in the DXF file
 * @param   {Array}    sectionTab         The texts are in the entities section
 * @returns {Array}    texts              An array of texts
 */
Parser.getTexts = function (sectionTab){

    var texts         = [],
        text          = undefined,
        sectionTab    = sectionTab.entities,
        textBool      = false;

    sectionTab.forEach(function (line, li){
        if(line == 'TEXT' || line == 'MTEXT'){
            textBool = true;
            text = new Text();
        }
        else if(textBool == true && line == '  8') text.setLayer(sectionTab[li+1]);
        else if(textBool == true && line == ' 10') {
            var point = new Point();
            point.setX(parseFloat(sectionTab[li + 1]));
            point.setY(parseFloat(sectionTab[li + 3]));
            text.setPoint(point);
        }
        else if(textBool == true && line == '  1') {
            text.setContents(sectionTab[li+1]);
            text.contentsParse();
        }
        else if(
            textBool == true &&
            text.layer != 'defaultLayer' &&
            text.contents != 'defaultContents' &&
            text.point != undefined

        ){
            textBool = false;
            if(text.contents !== ''){
                if(!texts[text.layer]) texts[text.layer] = [text];
                else texts[text.layer].push(text);
            } texts.push(text);
        }
    });
    return texts;
};

/**
 * Get Parameters : the origin point of the view, its center point and its rotate angle
 * @param   {Array}    sectionTab     The parameters are in the tables section
 * @returns {Object}   params         originPoint, viewCenterPoint, rotateAngle
 */
Parser.getParameters = function (sectionTab) {

    var params     = {originPoint: undefined, viewCenterPoint: undefined, rotateAngle: undefined},
        sectionTab = sectionTab.tables,
        vPort      = false;

    sectionTab.forEach(function (line, li) {
        if (line == 'AcDbViewportTableRecord') vPort = true;

        else if (vPort == true && line == ' 12'){
            var viewCenterPoint = new Point();
            viewCenterPoint.setX(parseFloat(sectionTab[li + 1]));
            viewCenterPoint.setY(parseFloat(sectionTab[li + 3]));
            params.viewCenterPoint = viewCenterPoint;
        }
        else if (vPort == true && line == ' 13'){
            var originPoint = new Point();
            originPoint.setX(parseFloat(sectionTab[li + 1]));
            originPoint.setY(parseFloat(sectionTab[li + 3]));
            params.originPoint = originPoint;
        }
        else if (vPort == true && line == ' 51') params.rotateAngle = parseFloat(sectionTab[li + 1]);
        else if (
            vPort == true && params.rotateAngle != undefined &&
            params.originPoint != undefined &&
            params.viewCenterPoint != undefined)
        {
            vPort = false;
        }
    });
    return params;
};

/**
 * Get the layers of the appropriate entities in the DXF file
 * @param    {Array}    sectionTab     The specific layers are in the entities section
 * @param    {Array}    tabEnt         You can put "text","polygon" or "circle" in the tabEnt (all by default)
 * @returns  {Array}    layers
 */
Parser.getLayersByEntities = function (sectionTab, tabEnt){

    var layers     = [],
        tabTmp     = tabEnt || 'all',
        ent        = false;

    if(tabTmp === 'all') layers = Parser.getAllLayers(sectionTab);
    else{
        var sectionTab = sectionTab.entities,
            tabEnt     = [];

        if (tabTmp.indexOf("text") !== -1) tabEnt.push("MTEXT", "TEXT");
        if (tabTmp.indexOf("polygon") !== -1) tabEnt.push("LWPOLYLINE");
        if (tabTmp.indexOf("circle") !== -1) tabEnt.push("CIRCLE");

        sectionTab.forEach(function (line, li){
            if(tabEnt.indexOf(line) !== -1) ent = true;
            else if(ent === true && line == '  8'){
                if(layers.indexOf(sectionTab[li+1].replace(/ {1,}/g,"")) === -1) layers.push(sectionTab[li+1].replace(/ {1,}/g,""));
            }
        });
    }
    return layers;
};

/**
 * Get all layers of the DXF file
 * @param   {Array}    sectionTab     All layers are in the tables section
 * @returns {Array}    layer
 */
Parser.getAllLayers = function (sectionTab){

    var layers       = [],
        sectionTab   = sectionTab.tables,
        getLayer     = false;

    sectionTab.forEach(function (line, li){
        if(line === "AcDbLayerTableRecord") getLayer = true;
        else if(getLayer === true && line === '  2'){
            if(layers.indexOf(sectionTab[li+1].replace(/ {1,}/g,"")) === -1){
                layers.push(sectionTab[li+1].replace(/ {1,}/g,""));
                getLayer = false;
            }
        }
    });
    return layers;
};

/**
 * Established a mapping between polygons and texts
 * @param    {object}    polygons
 * @param    {object}    texts
 * @returns  {Array}     mapping
 */
Parser.makeMappings = function (polygons, texts){

    var mappings = [];

    texts.forEach(function (text){
        polygons.forEach(function (polygon, p){
            if(polygon.points !== undefined){
                if(text.point.isInside(polygon.points)){
                    if(!mappings[p]) mappings[p] = {polygon : polygon, texts : [text]};
                    else mappings[p].texts.push(text);
                }
            }
        });
    });
    return mappings;
};

/**
 * Get the polygons of the DXF file which does not have text
 * @param   {Array}  polygons
 * @param   {Array}  texts
 * @returns {Array}  polygonWithoutText
 */
Parser.getPolygonsWithoutText = function (polygons, texts){

    var polygonWithoutText = [];

    polygons.forEach(function(polygon){

        var textInPolygon = [];

        texts.forEach(function (text, t){
            if(polygon.points !== undefined){
                if(text.point.isInside(polygon.points)) textInPolygon.push(t);
            }
        });
        if (textInPolygon.length === 0) polygonWithoutText.push(polygon);
    });
    return polygonWithoutText;
};

/**
 * Get the Texts of the DXF file which does not have polygon
 * @param   {Array}  texts
 * @param   {Array}  polygons
 * @returns {Array}  textsWithoutPolygon
 */
Parser.getTextsWithoutPolygon = function (texts, polygons){

    var textsWithoutPolygon = [];

    texts.forEach(function(text){

        var polygonWithText = [];

        polygons.forEach(function (polygon, p){
            if(polygon.points !== undefined){
                if(text.point.isInside(polygon.points)) polygonWithText.push(p);
            }
        });
        if (polygonWithText.length === 0) textsWithoutPolygon.push(text);
    });
    return textsWithoutPolygon;
};

/**
 * Return the min x,z  and the max x,y of the polygon's array
 * @param   {Array}     polygons
 * @returns {Object}    {min: point, max: point}
 */
Parser.getDimensions = function (polygons){

    var minPoint = new Point(),
        maxPoint = new Point();

    polygons.forEach(function (polygon, p) {
        polygon.points.forEach(function (tpoint, i) {
            minPoint.x = tpoint.x < minPoint.x ? tpoint.x : (i === 0 && p === 0 ? tpoint.x : minPoint.x);
            minPoint.y = tpoint.y < minPoint.y ? tpoint.y : (i === 0 && p === 0 ? tpoint.y : minPoint.y);
            maxPoint.x = tpoint.x > maxPoint.x ? tpoint.x : (i === 0 && p === 0 ? tpoint.x : maxPoint.x);
            maxPoint.y = tpoint.y > maxPoint.y ? tpoint.y : (i === 0 && p === 0 ? tpoint.y : maxPoint.y);
        });
    });
    return {
        'min': minPoint,
        'max': maxPoint
    }
};

module.exports = Parser;
<|endoftext|>


<commit_before>'use strict';

var
  path = require('path'),
  fs = require('fs'),
  stream = require('stream'),
  _ = require('lodash'),
  Q = require('q'),
  FS = require('q-io/fs'),
  storage = require('./storage'),
  converter = require('./converter'),
  debug = require('debug')('pictor:main'),
  DEBUG = debug.enabled;

var
  tempDir = '/tmp/pictor/temp',
  presets = require('./presets'),
  converters = {},
  dataStorage,
  cacheStorage;

function _getTempPath(prefix, suffix) {
  return path.join(tempDir, [
    prefix || '',
    Date.now().toString(36),
    '-',
    Math.random().toString(36).substring(2), // remove leading '0.'
    '-',
    process.pid,
    suffix || ''
  ].join(''));
}

/**
 * generate variant id based on source id.
 *
 * @param {string} id source id
 * @param {string} [variation]
 * @param {string} [ext]
 * @returns {string}
 * @private
 */
function _getVariantId(id, variation, ext) {
  // XXX: storage providers handle this? or not???
  // ex. cacheStorage.getVariantId(id, variation, ext);
  var variantId = id + '.d';
  if (variation) {
    variantId += '/' + variation;
  }
  if (ext) {
    variantId += '.' + ext;
  }
  return variantId;
}

/**
 * delete all variants from cache storage.
 *
 * @param {string} id
 * @returns {promise} success or not
 * @private
 */
function _deleteVariantFiles(id) {
  // XXX: storage providers handle this? or not???
  // ex. cacheStorage.deleteVariantsFiles(id);
  // delete files with prefix(or delete directory)
  return cacheStorage.deleteFile(_getVariantId(id));
}

//
//
//

/**
 * @class PictorFile
 * @property {string} id identifier
 * @property {string} source source identifier(only if this file is variant)
 * @property {string} url redirect url
 * @property {stream} stream stream object
 * @property {string} file local file path
 * @property {string} type mime type
 * @property {string} disposition 'inline', 'attachment'
 */
function PictorFile() {
} // DUMMY!

//
// CRUD operations for common files
//

/**
 * put a file.
 *
 * delete the old file and all its variants.
 *
 * NOTE: this always overwrites existing file.
 *
 * @param {string} id file identifier
 * @param {string|stream} file local file path or readable stream
 * @returns {promise.<PictorFile>}
 */
function putFile(id, file) {
  DEBUG && debug('put file:', id, '--->', file);

  return _deleteVariantFiles(id)
    .fail(function () {
      //if(err instanceof NotFoundError) { return true; } else throw err;
      return true;
    })
    .then(function () {
      // XXX: handle stream
      if (file instanceof stream.Readable) {
        var d = Q.defer();
        var tempFilePath = _getTempPath(null, id);
        var tempFileStream = fs.createWriteStream(tempFilePath)
          .on('error', function (err) {
            return d.reject(err);
          })
          .on('finish', function () {
            return d.resolve(dataStorage.putFile(id, tempFilePath));
            // TODO: delete tempFilePath
          });
        file.pipe(tempFileStream);
        return d.promise;
      }
      return dataStorage.putFile(id, file);
    })
    .then(function (result) {
      // XXX:
      result.id = id;
      // delete result.file
      // delete result.stream
      return result;
    });
}

/**
 * get a file.
 *
 * @param {string} id
 * @returns {promise.<PictorFile>}
 */
function getFile(id) {
  return dataStorage.getFile(id)
    .then(function (result) {
      // XXX:
      result.id = id;
      // delete result.file
      // delete result.stream
      return result;
    });
}

/**
 * delete a file and its variants.
 *
 * @param {string} id
 * @returns {promise} success or not
 */
function deleteFile(id) {
  return _deleteVariantFiles(id)
    .fail(function () {
      //if(err instanceof NotFoundError) { return true; } else throw err;
      return true;
    })
    .then(function () {
      return dataStorage.deleteFile(id);
    });
}

/**
 * EXPERIMENTAL: rename a file.
 *
 * NOTE: all variants of the file are deleted.
 *
 * @param {string} id
 * @param {string} targetId
 * @returns {Promise} success or not
 */
function renameFile(id, targetId) {
  return _deleteVariantFiles(id)
    .fail(function () {
      //if(err instanceof NotFoundError) { return true; } else throw err;
      return true;
    })
    .then(function () {
      return dataStorage.renameFile(id, targetId);
    });
}

/**
 * EXPERIMENTAL: list files match the given criteria.
 *
 * @param {*} [criteria]
 * @param {string} [criteria.prefix]
 * @param {string} [criteria.format]
 * @param {number} [criteria.skip]
 * @param {number} [criteria.limit]
 * @returns {Promise.<Array.<PictorFile>>} matched files
 */
function listFiles(criteria) {
  return dataStorage.listFiles(criteria);
}

/**
 * convert a file.
 *
 * @param {*} opts various converter specific params
 * @returns {promise.<PictorFile>}
 */
function convertFile(opts) {
  // XXX: need cleanup! this is the most puzzling code in pictor :S

  // 'preset' converter is special one!
  if (opts.converter === 'preset') {
    if (!opts.preset) {
      throw 'required_param_preset';
    }
    var preset = presets[opts.preset];
    if (!preset) {
      throw 'invalid_param_preset';
    }
    // overrides preset with specified params
    opts = _.extend(opts, preset);
    DEBUG && debug('*** convert - preset', opts.preset, preset, '--->', opts);
  }

  var converter = converters[opts.converter];
  if (!converter) {
    throw 'invalid_param_converter';
  }

  opts.src = opts.id; // getExtension refer opts.src to determine default ext.
  opts.format = converter.getExtension(opts);
  opts.variant = converter.getVariation(opts) + '.' + opts.format;

  var variantId = _getVariantId(opts.id || opts.converter, opts.variant);

  DEBUG && debug('*** convert - prepare', opts, '--->', variantId);

  // get variant from cache storage
  return cacheStorage.getFile(variantId)
    .fail(function () {
      // variant not in cache storage
      DEBUG && debug('*** convert - variant not in cache', variantId);

      // TODO: better way to handle various input/ouput of converter?
      // 0..n input -> 1..m output

      // prepare temp file for output
      DEBUG && debug('*** convert - prepare dst', opts.dst);
      opts.dst = _getTempPath(null, opts.variant);

      // prepare for input
      return Q.resolve(opts)
        .then(function (opts) {
          // 2.3 no input required(holder converter)
          DEBUG && debug('*** convert - no src');
          if (!opts.id) {
            opts.src = null;
            return opts;
          }
          // input required(most converters) -> get source from data storage
          DEBUG && debug('*** convert - get src', opts.id);
          return dataStorage.getFile(opts.id)
            .then(function (src) {
              opts.src = src.file || src.stream;
              // prepare temp file for output
              DEBUG && debug('*** convert - prepare dst', opts.dst);
              return opts;
            });
        })
        .then(function (opts) {
          // convert source to temp file
          DEBUG && debug('*** convert - converting...', opts);
          return converter.convert(opts);
        })
        .then(function () {
          // put temp file into cache storage
          DEBUG && debug('*** convert - save dst into cache', variantId);
          return cacheStorage.putFile(variantId, opts.dst);
          // TODO: delete tempFilePath
        });
    })
    .then(function (result) {
      // variant in cache storage
      DEBUG && debug('*** convert - variant in cache', result);
      result.id = opts.id;
      result.variant = opts.variant;
      // delete result.file
      // delete result.stream
      return result;
    });
}

/**
 * get a variant file.
 *
 * @param {string} id
 * @param {string} variant
 * @returns {promise.<PictorFile>}
 */
function getVariantFile(id, variant) {
  return cacheStorage.getFile(_getVariantId(id, variant))
    .then(function (result) {
      result.id = id;
      result.variant = variant;
      return result;
    });
}

//
//
//

/**
 * configure pictor main module.
 *
 * `config` contains:
 *
 *    - {string} tempDir
 *    - {object} presets
 *    - {object} data
 *    - {object} cache
 *
 * @param {object} config
 */
function configure(config) {
  DEBUG && debug('configure pictor...');

  tempDir = config.tempDir || require('os').tmpdir();//'/tmp/pictor/temp';
  FS.makeTree(tempDir)
    .fail(function (err) {
      console.warn('** warning ** failed to create tempDir:', tempDir, err);
      tempDir = require('os').tmpdir();
    })
    .then(function () {
      DEBUG && debug('tempDir:', tempDir);
    })
    .done();

  _.extend(presets, config.presets);
  DEBUG && debug('presets: ', presets);

  if (config.converters) {
    converters = Object.keys(config.converters).reduce(function (result, name) {
      var opts = config.converters[name] || {};
      result[name] = converter.createConverter(name, opts);
      return result;
    }, {});
    DEBUG && debug('converters: ', Object.keys(converters));
  } else {
    console.warn('** waning ** no converters configured!');
  }

  if (!config.data) {
    console.error('** fatal ** no data storage configuration!');
    process.exit(1);
  }
  dataStorage = storage.createStorage(config.data.provider, config.data);

  if (!config.cache) {
    console.error('** fatal ** no cache storage configuration!');
    process.exit(1);
  }
  cacheStorage = storage.createStorage(config.cache.provider, config.cache);
}

module.exports = {
  presets: presets,
  putFile: putFile,
  deleteFile: deleteFile,
  getFile: getFile,
  renameFile: renameFile,
  listFiles: listFiles,
  convertFile: convertFile,
  getVariantFile: getVariantFile,
  configure: configure
};
<commit_msg>- add rotate converter and api. - add get converters, get presets api.<commit_after>'use strict';

var
  path = require('path'),
  fs = require('fs'),
  stream = require('stream'),
  _ = require('lodash'),
  Q = require('q'),
  FS = require('q-io/fs'),
  storage = require('./storage'),
  converter = require('./converter'),
  debug = require('debug')('pictor:main'),
  DEBUG = debug.enabled;

var
  tempDir = '/tmp/pictor/temp',
  presets = require('./presets'),
  converters = {},
  dataStorage,
  cacheStorage;

function _getTempPath(prefix, suffix) {
  return path.join(tempDir, [
    prefix || '',
    Date.now().toString(36),
    '-',
    Math.random().toString(36).substring(2), // remove leading '0.'
    '-',
    process.pid,
    suffix || ''
  ].join(''));
}

/**
 * generate variant id based on source id.
 *
 * @param {string} id source id
 * @param {string} [variation]
 * @param {string} [ext]
 * @returns {string}
 * @private
 */
function _getVariantId(id, variation, ext) {
  // XXX: storage providers handle this? or not???
  // ex. cacheStorage.getVariantId(id, variation, ext);
  var variantId = id + '.d';
  if (variation) {
    variantId += '/' + variation;
  }
  if (ext) {
    variantId += '.' + ext;
  }
  return variantId;
}

/**
 * delete all variants from cache storage.
 *
 * @param {string} id
 * @returns {promise} success or not
 * @private
 */
function _deleteVariantFiles(id) {
  // XXX: storage providers handle this? or not???
  // ex. cacheStorage.deleteVariantsFiles(id);
  // delete files with prefix(or delete directory)
  return cacheStorage.deleteFile(_getVariantId(id));
}

//
//
//

/**
 * @class PictorFile
 * @property {string} id identifier
 * @property {string} source source identifier(only if this file is variant)
 * @property {string} url redirect url
 * @property {stream} stream stream object
 * @property {string} file local file path
 * @property {string} type mime type
 * @property {string} disposition 'inline', 'attachment'
 */
function PictorFile() {
} // DUMMY!

//
// CRUD operations for common files
//

/**
 * put a file.
 *
 * delete the old file and all its variants.
 *
 * NOTE: this always overwrites existing file.
 *
 * @param {string} id file identifier
 * @param {string|stream} file local file path or readable stream
 * @returns {promise.<PictorFile>}
 */
function putFile(id, file) {
  DEBUG && debug('put file:', id, '--->', file);

  return _deleteVariantFiles(id)
    .fail(function () {
      //if(err instanceof NotFoundError) { return true; } else throw err;
      return true;
    })
    .then(function () {
      // XXX: handle stream
      if (file instanceof stream.Readable) {
        var d = Q.defer();
        var tempFilePath = _getTempPath(null, id);
        var tempFileStream = fs.createWriteStream(tempFilePath)
          .on('error', function (err) {
            return d.reject(err);
          })
          .on('finish', function () {
            return d.resolve(dataStorage.putFile(id, tempFilePath));
            // TODO: delete tempFilePath
          });
        file.pipe(tempFileStream);
        return d.promise;
      }
      return dataStorage.putFile(id, file);
    })
    .then(function (result) {
      // XXX:
      result.id = id;
      // delete result.file
      // delete result.stream
      return result;
    });
}

/**
 * get a file.
 *
 * @param {string} id
 * @returns {promise.<PictorFile>}
 */
function getFile(id) {
  return dataStorage.getFile(id)
    .then(function (result) {
      // XXX:
      result.id = id;
      // delete result.file
      // delete result.stream
      return result;
    });
}

/**
 * delete a file and its variants.
 *
 * @param {string} id
 * @returns {promise} success or not
 */
function deleteFile(id) {
  return _deleteVariantFiles(id)
    .fail(function () {
      //if(err instanceof NotFoundError) { return true; } else throw err;
      return true;
    })
    .then(function () {
      return dataStorage.deleteFile(id);
    });
}

/**
 * EXPERIMENTAL: rename a file.
 *
 * NOTE: all variants of the file are deleted.
 *
 * @param {string} id
 * @param {string} targetId
 * @returns {Promise} success or not
 */
function renameFile(id, targetId) {
  return _deleteVariantFiles(id)
    .fail(function () {
      //if(err instanceof NotFoundError) { return true; } else throw err;
      return true;
    })
    .then(function () {
      return dataStorage.renameFile(id, targetId);
    });
}

/**
 * EXPERIMENTAL: list files match the given criteria.
 *
 * @param {*} [criteria]
 * @param {string} [criteria.prefix]
 * @param {string} [criteria.format]
 * @param {number} [criteria.skip]
 * @param {number} [criteria.limit]
 * @returns {Promise.<Array.<PictorFile>>} matched files
 */
function listFiles(criteria) {
  return dataStorage.listFiles(criteria);
}

/**
 * convert a file.
 *
 * @param {*} opts various converter specific params
 * @returns {promise.<PictorFile>}
 */
function convertFile(opts) {
  // XXX: need cleanup! this is the most puzzling code in pictor :S

  // 'preset' converter is special one!
  if (opts.converter === 'preset') {
    if (!opts.preset) {
      throw 'required_param_preset';
    }
    var preset = presets[opts.preset];
    if (!preset) {
      throw 'invalid_param_preset';
    }
    // overrides preset with specified params
    opts = _.extend(opts, preset);
    DEBUG && debug('*** convert - preset', opts.preset, preset, '--->', opts);
  }

  var converter = converters[opts.converter];
  if (!converter) {
    throw 'invalid_param_converter';
  }

  opts.src = opts.id; // getExtension refer opts.src to determine default ext.
  opts.format = converter.getExtension(opts);
  opts.variant = converter.getVariation(opts) + '.' + opts.format;

  var variantId = _getVariantId(opts.id || opts.converter, opts.variant);

  DEBUG && debug('*** convert - prepare', opts, '--->', variantId);

  // get variant from cache storage
  return cacheStorage.getFile(variantId)
    .fail(function () {
      // variant not in cache storage
      DEBUG && debug('*** convert - variant not in cache', variantId);

      // TODO: better way to handle various input/ouput of converter?
      // 0..n input -> 1..m output

      // prepare temp file for output
      DEBUG && debug('*** convert - prepare dst', opts.dst);
      opts.dst = _getTempPath(null, opts.variant);

      // prepare for input
      return Q.resolve(opts)
        .then(function (opts) {
          // 2.3 no input required(holder converter)
          DEBUG && debug('*** convert - no src');
          if (!opts.id) {
            opts.src = null;
            return opts;
          }
          // input required(most converters) -> get source from data storage
          DEBUG && debug('*** convert - get src', opts.id);
          return dataStorage.getFile(opts.id)
            .then(function (src) {
              opts.src = src.file || src.stream;
              // prepare temp file for output
              DEBUG && debug('*** convert - prepare dst', opts.dst);
              return opts;
            });
        })
        .then(function (opts) {
          // convert source to temp file
          DEBUG && debug('*** convert - converting...', opts);
          return converter.convert(opts);
        })
        .then(function () {
          // put temp file into cache storage
          DEBUG && debug('*** convert - save dst into cache', variantId);
          return cacheStorage.putFile(variantId, opts.dst);
          // TODO: delete tempFilePath
        });
    })
    .then(function (result) {
      // variant in cache storage
      DEBUG && debug('*** convert - variant in cache', result);
      result.id = opts.id;
      result.variant = opts.variant;
      // delete result.file
      // delete result.stream
      return result;
    });
}

/**
 * get a variant file.
 *
 * @param {string} id
 * @param {string} variant
 * @returns {promise.<PictorFile>}
 */
function getVariantFile(id, variant) {
  return cacheStorage.getFile(_getVariantId(id, variant))
    .then(function (result) {
      result.id = id;
      result.variant = variant;
      return result;
    });
}

/**
 * get of all available converters.
 *
 * @returns {Array.<String>}
 */
function getConverters() {
    return Object.keys(converters);
}

/**
 * get all available presets.
 *
 * @returns {Array.<String>}
 */
function getPresets() {
    return Object.keys(presets);
}

//
//
//

/**
 * configure pictor main module.
 *
 * `config` contains:
 *
 *    - {string} tempDir
 *    - {object} presets
 *    - {object} data
 *    - {object} cache
 *
 * @param {object} config
 */
function configure(config) {
  DEBUG && debug('configure pictor...');

  tempDir = config.tempDir || require('os').tmpdir();//'/tmp/pictor/temp';
  FS.makeTree(tempDir)
    .fail(function (err) {
      console.warn('** warning ** failed to create tempDir:', tempDir, err);
      tempDir = require('os').tmpdir();
    })
    .then(function () {
      DEBUG && debug('tempDir:', tempDir);
    })
    .done();

  _.extend(presets, config.presets);
  DEBUG && debug('presets: ', presets);

  if (config.converters) {
    converters = Object.keys(config.converters).reduce(function (result, name) {
      var opts = config.converters[name] || {};
      result[name] = converter.createConverter(name, opts);
      return result;
    }, {});
    DEBUG && debug('converters: ', Object.keys(converters));
  } else {
    console.warn('** waning ** no converters configured!');
  }

  if (!config.data) {
    console.error('** fatal ** no data storage configuration!');
    process.exit(1);
  }
  dataStorage = storage.createStorage(config.data.provider, config.data);

  if (!config.cache) {
    console.error('** fatal ** no cache storage configuration!');
    process.exit(1);
  }
  cacheStorage = storage.createStorage(config.cache.provider, config.cache);
}

module.exports = {
  presets: presets,
  putFile: putFile,
  deleteFile: deleteFile,
  getFile: getFile,
  renameFile: renameFile,
  listFiles: listFiles,
  convertFile: convertFile,
  getVariantFile: getVariantFile,
  getConverters: getConverters,
  getPresets: getPresets,
  configure: configure
};
<|endoftext|>


<commit_before>import Ajv from 'ajv';

/**
 * Schema validation middleware and helper functions
 */
let schema = {

    compileJsonSchema(inputSchema) {
        let ajv = new Ajv();
        return ajv.compile(inputSchema);
    },

    validateJson(compiledSchema, jsonBody) {
        return compiledSchema(jsonBody);
    },

    getSchemaError(compiledSchema) {
        let ajv = new Ajv();
        return ajv.errorsText(compiledSchema.errors);
    },

    validateBody(inputSchema) {
        return function (req, res, next) {
            let compiledSchema = schema.compileJsonSchema(inputSchema);
            let valid = schema.validateJson(compiledSchema, req.body);
            if (!valid) {
                return res.status(400).send({error: schema.getSchemaError(valid)});
            } else {
                return next();
            }
        };
    }

};

export default schema;
<commit_msg>Return schema validation objects instead of string on error.<commit_after>import Ajv from 'ajv';

/**
 * Schema validation middleware and helper functions
 */
let schema = {

    compileJsonSchema(inputSchema) {
        let ajv = new Ajv();
        return ajv.compile(inputSchema);
    },

    validateJson(compiledSchema, jsonBody) {
        return compiledSchema(jsonBody);
    },

    validateBody(inputSchema) {
        return function (req, res, next) {
            let compiledSchema = schema.compileJsonSchema(inputSchema);
            let valid = schema.validateJson(compiledSchema, req.body);
            if (!valid) {
                return res.status(400).send({error: compiledSchema.errors});
            } else {
                return next();
            }
        };
    }

};

export default schema;
<|endoftext|>


<commit_before>var path = require('path');
var { Storage } = require('@google-cloud/storage');
var Promise = require('rsvp').Promise;
var chunk = require('lodash.chunk');

module.exports = function uploadToGCS(plugin, config) {
  const storage = new Storage(config.gcloud);
  const bucket = storage.bucket(config.bucket);

  const chunkedFilePaths = chunk(config.filePaths, 50);

  return chunkedFilePaths.reduce(function (previous, chunk) {
    return previous.then(function () {
      return Promise.all(
        chunk.map(function (filePath) {
          var basePath = path.join(config.fileBase, filePath);

          var isGzipped = config.gzippedFilePaths.indexOf(filePath) !== -1;

          return new Promise(function (resolve, reject) {
            var destinationFilePath = config.bucketFolder
              ? path.join(config.bucketFolder, filePath)
              : filePath;
            if (path.sep === '\\') {
              destinationFilePath = destinationFilePath.replace(/\\/g, '/');
            }
            var metadata = Object.assign(
              {},
              isGzipped ? { contentEncoding: 'gzip' } : {},
              config.metadata
            );

            return bucket.upload(
              basePath,
              {
                destination: destinationFilePath,
                metadata: metadata,
                gzip: !isGzipped,
              },
              function (err, file) {
                if (err) {
                  return reject(err);
                }

                // for uniform permission buckets this fails because it tries to get/set an ACL on the object
                if (config.makePublic) {
                  file.makePublic(function (err, res) {
                    if (err) {
                      return reject(err);
                    }
                  });
                }

                // verify the uploaded file
                file.download({ validation: false }, function (err, contents) {
                  if (err) {
                    return reject(err);
                  }

                  plugin.log('✔  ' + filePath, { verbose: true });
                  resolve(contents.toString('utf8'));
                });
              }
            );
          });
        })
      );
    });
  }, Promise.resolve());
};
<commit_msg>chore: unused var<commit_after>var path = require('path');
var { Storage } = require('@google-cloud/storage');
var Promise = require('rsvp').Promise;
var chunk = require('lodash.chunk');

module.exports = function uploadToGCS(plugin, config) {
  const storage = new Storage(config.gcloud);
  const bucket = storage.bucket(config.bucket);

  const chunkedFilePaths = chunk(config.filePaths, 50);

  return chunkedFilePaths.reduce(function (previous, chunk) {
    return previous.then(function () {
      return Promise.all(
        chunk.map(function (filePath) {
          var basePath = path.join(config.fileBase, filePath);

          var isGzipped = config.gzippedFilePaths.indexOf(filePath) !== -1;

          return new Promise(function (resolve, reject) {
            var destinationFilePath = config.bucketFolder
              ? path.join(config.bucketFolder, filePath)
              : filePath;
            if (path.sep === '\\') {
              destinationFilePath = destinationFilePath.replace(/\\/g, '/');
            }
            var metadata = Object.assign(
              {},
              isGzipped ? { contentEncoding: 'gzip' } : {},
              config.metadata
            );

            return bucket.upload(
              basePath,
              {
                destination: destinationFilePath,
                metadata: metadata,
                gzip: !isGzipped,
              },
              function (err, file) {
                if (err) {
                  return reject(err);
                }

                // for uniform permission buckets this fails because it tries to get/set an ACL on the object
                if (config.makePublic) {
                  file.makePublic(function (err) {
                    if (err) {
                      return reject(err);
                    }
                  });
                }

                // verify the uploaded file
                file.download({ validation: false }, function (err, contents) {
                  if (err) {
                    return reject(err);
                  }

                  plugin.log('✔  ' + filePath, { verbose: true });
                  resolve(contents.toString('utf8'));
                });
              }
            );
          });
        })
      );
    });
  }, Promise.resolve());
};
<|endoftext|>


<commit_before>class ListOption extends HTMLElement {
    constructor() {
        super();
        this.connected = false;
    }

    static get observedAttributes() {
        return ['selected'];
    }

    connectedCallback() {
        this.init();
        this.render();

        this.addEventListener('click', () => {
            this.selected = !this.selected;
            const event = document.createEvent('HTMLEvents');
            event.initEvent('change', true, false);
            this.dispatchEvent(event);
        });
        this.connected = true;
    }

    disconnectedCallback() {
        this.removeEventListener('click');
    }

    attributeChangedCallback() {
        if (this.connected) {
            this.render();
        }
    }

    get label() {
        return this.getAttribute('label');
    }

    get selected() {
        return this.hasAttribute('selected');
    }

    set selected(isSelected) {
        if (isSelected) {
            this.setAttribute('selected', 'selected')
        } else {
            this.removeAttribute('selected')
        }
    }

    init() {
        const container = document.createElement('div');
        container.className = 'list-option';

        const checkbox = document.createElement('input');
        checkbox.type = 'checkbox';

        const label = document.createElement('span');
        label.textContent = this.label;

        container.appendChild(checkbox);
        container.appendChild(label);
        this.appendChild(container);
    }

    render() {
        this.querySelector('input').checked = this.selected;
    }
}

window.customElements.define('list-option', ListOption);<commit_msg>Added pointer cursor style to list option element<commit_after>class ListOption extends HTMLElement {
    constructor() {
        super();
        this.connected = false;
    }

    static get observedAttributes() {
        return ['selected'];
    }

    connectedCallback() {
        this.init();
        this.render();

        this.addEventListener('click', () => {
            this.selected = !this.selected;
            const event = document.createEvent('HTMLEvents');
            event.initEvent('change', true, false);
            this.dispatchEvent(event);
        });
        this.connected = true;
    }

    disconnectedCallback() {
        this.removeEventListener('click');
    }

    attributeChangedCallback() {
        if (this.connected) {
            this.render();
        }
    }

    get label() {
        return this.getAttribute('label');
    }

    get selected() {
        return this.hasAttribute('selected');
    }

    set selected(isSelected) {
        if (isSelected) {
            this.setAttribute('selected', 'selected')
        } else {
            this.removeAttribute('selected')
        }
    }

    init() {
        const container = document.createElement('div');
        container.className = 'list-option';
        container.style.cursor = 'pointer';

        const checkbox = document.createElement('input');
        checkbox.type = 'checkbox';

        const label = document.createElement('span');
        label.textContent = this.label;

        container.appendChild(checkbox);
        container.appendChild(label);
        this.appendChild(container);
    }

    render() {
        this.querySelector('input').checked = this.selected;
    }
}

window.customElements.define('list-option', ListOption);<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 3CSI All Rights Reserved
 *
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF 3CSI
 * The copyright notice above does not evidence any actual or intended
 * publication of such source code.
 */
var dist = require('broccoli-dist-es6-module'),
    mergeTrees = require('broccoli-merge-trees'),
    pickFiles = require('broccoli-static-compiler'),
    concat = require('broccoli-concat'),
    uglify = require('broccoli-uglify-js'),
    fs = require("fs");

var license = fs.readFileSync('./LICENSE', "utf8").split('\n').map(function (l) {
    return '//' + l;
}).join('\n');

// build and only pick the global output
var distFiles = pickFiles(dist('src', {
    main: 'bbcode',
    global: 'bbcode',
    packageName: 'bbcode'
}), {
    srcDir: '/globals',
    files: ['main.js'],
    destDir: '/'
});

var tree = concat(distFiles,
    {
        inputFiles: [
            'main.js'
        ],
        outputFile: '/bbcode.js',
        header: license
    });

var min = concat(uglify(tree, {mangle: true}), {
    inputFiles: [
        'bbcode.js'
    ],
    outputFile: '/bbcode.min.js',
    header: license
});

module.exports = mergeTrees([tree, min]);
<commit_msg>removed superfluous header<commit_after>var dist = require('broccoli-dist-es6-module'),
    mergeTrees = require('broccoli-merge-trees'),
    pickFiles = require('broccoli-static-compiler'),
    concat = require('broccoli-concat'),
    uglify = require('broccoli-uglify-js'),
    fs = require("fs");

var license = fs.readFileSync('./LICENSE', "utf8").split('\n').map(function (l) {
    return '//' + l;
}).join('\n');

// build and only pick the global output
var distFiles = pickFiles(dist('src', {
    main: 'bbcode',
    global: 'bbcode',
    packageName: 'bbcode'
}), {
    srcDir: '/globals',
    files: ['main.js'],
    destDir: '/'
});

var tree = concat(distFiles,
    {
        inputFiles: [
            'main.js'
        ],
        outputFile: '/bbcode.js',
        header: license
    });

var min = concat(uglify(tree, {mangle: true}), {
    inputFiles: [
        'bbcode.js'
    ],
    outputFile: '/bbcode.min.js',
    header: license
});

module.exports = mergeTrees([tree, min]);
<|endoftext|>


<commit_before>var slackMsgs = require('./slackMsgs.js');
var url = require('url');
var key = process.env.HUBOT_TRELLO_KEY;

var request = require(request - promise);

module.exports = function (robot) {

	robot.respond(/trello get token/i, function (res_r) {

		let scope = 'read,write,account';
		let name = 'Hubot';
		let expr = '30days';
		let cb_method = 'fragment';
		let return_url = 'https://andreasbot.herokuapp.com/hubot/trello-token';
		let url = `https://trello.com/1/authorize?expiration=${expr}&name=${name}&scope=${scope}&key=${key}&response_type=token&callback_method=${cb_method}&return_url=${return_url}`;
		var msg = slackMsgs.basicMessage();

		msg.attachments[0].pretext = "Please get a token to authorize your Trello account";
		msg.attachments[0].title = "Trello Token";
		msg.attachments[0].title_link = url;
		msg.attachments[0].text = "Copy the token from the link above and run\n *trello add token <YOUR TOKEN>*";
		msg.attachments[0].footer = "Trello";
		msg.attachments[0].footer_icon = "https://d2k1ftgv7pobq7.cloudfront.net/meta/u/res/images/b428584f224c42e98d158dad366351b0/trello-mark-blue.png";
		res_r.send(msg);
	})

	robot.router.get('/hubot/trello-token', function (req, res) {
		// TODO: do something with the token
		// robot.logger.info(res.fragment);	// undefined
		// var type = window.location.hash.substr(1);
		// robot.logger.info(type);
		res.send(`
Token succesfuly received. You can now close the window.
\n
					<button onclick=window.close()>close</button>`)
	});

	robot.respond(/trello add token (.*)/i, function (res_r) {
		var token = res_r.match[1];
		//***IMPORTANT***
		// the .env assignment doesnt work with HEROKU!
		// must set up a heroku client and communicate through their api
		process.env['HUBOT_TRELLO_TOKEN'] = token;
	})

	robot.respond(/trello request/, function (res_r) {
		var options = {
			uri: 'https://trello.com/1/authorize?expiration=30days&name=Hubot&scope=read,write,account&key=51def9cb08cf171cd0970d8607ad8f97&response_type=token&callback_method=postMessage&return_url=https://andreasbot.herokuapp.com/hubot/trello-token',
			headers: {
				'User-Agent': 'Request-Promise'
			},
			json: true // Automatically parses the JSON string in the response
		};

		request(options)
			.then(function (res) {
				robot.logger.info(res);
			})
			.catch(function (err) {
				robot.logger.error(err)
				// API call failed...
			});
	})
}<commit_msg>add html page<commit_after>var slackMsgs = require('./slackMsgs.js');
var url = require('url');
var key = process.env.HUBOT_TRELLO_KEY;

var request = require(request-promise);

module.exports = function (robot) {

	robot.respond(/trello get token/i, function (res_r) {

		let scope = 'read,write,account';
		let name = 'Hubot';
		let expr = '30days';
		let cb_method = 'fragment';
		let return_url = 'https://andreasbot.herokuapp.com/hubot/trello-token';
		let url = `https://trello.com/1/authorize?expiration=${expr}&name=${name}&scope=${scope}&key=${key}&response_type=token&callback_method=${cb_method}&return_url=${return_url}`;
		var msg = slackMsgs.basicMessage();

		msg.attachments[0].pretext = "Please get a token to authorize your Trello account";
		msg.attachments[0].title = "Trello Token";
		msg.attachments[0].title_link = url;
		msg.attachments[0].text = "Copy the token from the link above and run\n *trello add token <YOUR TOKEN>*";
		msg.attachments[0].footer = "Trello";
		msg.attachments[0].footer_icon = "https://d2k1ftgv7pobq7.cloudfront.net/meta/u/res/images/b428584f224c42e98d158dad366351b0/trello-mark-blue.png";
		res_r.send(msg);
	})

	robot.router.get('/hubot/trello-token', function (req, res) {
		// TODO: do something with the token
		// robot.logger.info(res.fragment);	// undefined
		// var type = window.location.hash.substr(1);
		// robot.logger.info(type);
		res.send(`
Token succesfuly received. You can now close the window.
\n
					<button onclick=window.close()>close</button>`)
	});

	robot.respond(/trello add token (.*)/i, function (res_r) {
		var token = res_r.match[1];
		//***IMPORTANT***
		// the .env assignment doesnt work with HEROKU!
		// must set up a heroku client and communicate through their api
		process.env['HUBOT_TRELLO_TOKEN'] = token;
	})

	robot.respond(/trello request/, function (res_r) {
		var options = {
			uri: 'https://trello.com/1/authorize?expiration=30days&name=Hubot&scope=read,write,account&key=51def9cb08cf171cd0970d8607ad8f97&response_type=token&callback_method=postMessage&return_url=https://andreasbot.herokuapp.com/hubot/trello-token',
			headers: {
				'User-Agent': 'Request-Promise'
			},
			json: true // Automatically parses the JSON string in the response
		};

		request(options)
			.then(function (res) {
				robot.logger.info(res);
			})
			.catch(function (err) {
				robot.logger.error(err)
				// API call failed...
			});
	})
		robot.respond(/trello request 2/, function (res_r) {
		var options = {
			uri: 'https://trello.com/1/authorize',
			headers: {
				'User-Agent': 'Request-Promise'
			},
			json: true // Automatically parses the JSON string in the response
		};

		request(options)
			.then(function (res) {
				robot.logger.info(res);
			})
			.catch(function (err) {
				robot.logger.error(err)
				// API call failed...
			});
	})
}<|endoftext|>


<commit_before>/* eslint-env mocha, jasmine */
/* global expect */

import React, { Component, PropTypes } from 'react';
import FormsyText from '../src/FormsyText';
import TextField from 'material-ui/TextField';
import { Simulate } from 'react-addons-test-utils';
import { mountTestForm } from './support';
import { Form } from 'formsy-react';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import { mount } from 'enzyme';

function makeChildrenFn(props) {
  const fn = () => (
    <FormsyText ref="text"
      name="text"
      validations="maxLength:10"
      validationErrors={{ maxLength: 'Text is too long' }}
      { ...props }
    />
  );
  fn.DisplayName = 'FormsyText';
  return fn;
}

const setup = (props) => {
  const childrenFn = makeChildrenFn(props);
  const formWrapper = mountTestForm(childrenFn);
  const formsyTextWrapper = formWrapper.find(FormsyText);
  return {
    formWrapper,
    formsyTextWrapper,
  };
};

class TestForm extends Component {

  static childContextTypes = {
    muiTheme: PropTypes.object.isRequired,
  };

  static propTypes = {
    children: PropTypes.node,
    defaultValue: PropTypes.string,
    value: PropTypes.string,
  }

  getChildContext() {
    return { muiTheme: getMuiTheme() };
  }

  componentWillMount() {
    const { value, defaultValue } = this.props;
    this.state = { value, defaultValue };
  }

  render() {
    const { value, defaultValue, children, ...extraProps } = { ...this.props, ...this.state };
    return (
      <Form { ...extraProps }>
        {children ? children : (
          <FormsyText ref="text" name="text"
            value={value}
            defaultValue={defaultValue}
          />
        )}
      </Form>
    );
  }
}

function makeTestParent(props) {
  const parent = mount(<TestForm {...props} />);
  const formWrapper = parent.find(Form);
  const formsyTextWrapper = parent.find(FormsyText);
  return { parent, formWrapper, formsyTextWrapper };
}

const fillInText = (wrapper, text) => {
  const inputDOM = wrapper.find('input').node;
  inputDOM.value = text;
  Simulate.change(inputDOM);
  Simulate.blur(inputDOM);
};

describe('FormsyText', () => {
  it('renders a material-ui TextField', () => {
    const { formsyTextWrapper } = setup();
    expect(formsyTextWrapper).to.have.descendants(TextField);
  });

  it('sends input to the form', () => {
    const { formsyTextWrapper, formWrapper } = setup();
    fillInText(formsyTextWrapper, 'some text');
    const formsyForm = formWrapper.find(Form).node;
    const formValues = formsyForm.getCurrentValues();
    expect(formValues.text).to.eq('some text');
  });

  it('renders validation information', () => {
    const { formsyTextWrapper, formWrapper } = setup();

    expect(formsyTextWrapper).to.not.contain.text('Text is too long');

    const formsyForm = formWrapper.find(Form).node;
    fillInText(formsyTextWrapper, 'toooooooo loooooong');
    formsyForm.validateForm();
    expect(formsyTextWrapper).to.contain.text('Text is too long');

    fillInText(formsyTextWrapper, 'just fine');
    formsyForm.validateForm();
    expect(formsyTextWrapper).to.not.contain.text('Text is too long');
  });

  describe('value properties handle', () => {
    describe('initial', () => {
      it('value', () => {
        const { formsyTextWrapper, formWrapper } = setup({
          value: 'VALUE',
        });
        const formsyForm = formWrapper.find(Form).node;
        let formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('VALUE');
        fillInText(formsyTextWrapper, 'some text');
        formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('some text');
      });

      it('defaultValue', () => {
        const { formsyTextWrapper, formWrapper } = setup({
          defaultValue: 'DEFAULT-VALUE',
        });
        const formsyForm = formWrapper.find(Form).node;
        let formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('DEFAULT-VALUE');
        fillInText(formsyTextWrapper, 'some text');
        formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('some text');
      });

      it('value + defaultValue', () => {
        const { formsyTextWrapper, formWrapper } = setup({
          value: 'VALUE',
          defaultValue: 'DEFAULT-VALUE',
        });
        const formsyForm = formWrapper.find(Form).node;
        let formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('VALUE');
        fillInText(formsyTextWrapper, 'some text');
        formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('some text');
      });

      it('propagates disabled status', () => {
        const wrapper = mount(
          <TestForm disabled={true} >
            <FormsyText
              name="text"
            />
          </TestForm>
        );

        const inputDOM = wrapper.find('input').node;
        expect(inputDOM.disabled).to.eq(true);

        // Next, we set `disabled` to false and check the DOM node updates accordingly
        wrapper.setProps({
          disabled: false,
        });
        expect(inputDOM.disabled).to.eq(false);
      });

      it('allows overriding disabled status locally', () => {
        let wrapper = mount(
          <TestForm disabled={true}>
            <FormsyText
              name="text"
              disabled={false}
            />
          </TestForm>
        );

        // Here we check we can disable a single input in a globally enabled form
        let inputDOM = wrapper.find('input').node;
        expect(inputDOM.disabled).to.eq(false);

        wrapper = mount(
          <TestForm disabled={false}>
            <FormsyText
              name="text"
              disabled={true}
            />
          </TestForm>
        );

        // Likewise, we are able to keep a specific input enabled even if the form is marked as disabled
        inputDOM = wrapper.find('input').node;
        expect(inputDOM.disabled).to.eq(true);
      });
    });

    describe('updating', () => {
      it('value', () => {
        const props = {
          value: 'VALUE',
        };
        const { parent, formWrapper, formsyTextWrapper } = makeTestParent(props);
        const formsyForm = formWrapper.node;
        parent.setState({ value: 'NEW VALUE' });
        let formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('NEW VALUE');
        fillInText(formsyTextWrapper, 'some text');
        formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('some text');
        parent.setState({ value: 'NEWER VALUE' });
        formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('NEWER VALUE');
      });

      it('defaultValue', () => {
        const props = {
          defaultValue: 'VALUE',
        };
        const { parent, formWrapper, formsyTextWrapper } = makeTestParent(props);
        const formsyForm = formWrapper.node;
        parent.setState({ defaultValue: 'NEW VALUE' });
        let formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('NEW VALUE');
        fillInText(formsyTextWrapper, 'some text');
        formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('some text');
        parent.setState({ defaultValue: 'NEWER VALUE' });
        // defaultValues does not override the typed in value.
        formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('some text');
      });

      it('calls onChange once per text update', () => {
        const calls = [];
        const { parent, formsyTextWrapper } = makeTestParent({
          onChange: (...args) => calls.push(args),
          value: 'initial',
        });

        const inputDOM = formsyTextWrapper.find('input').node;
        inputDOM.value = 'updated';
        parent.setState({ value: 'updated' });

        expect(calls.length).to.eq(1);
      });
    });

    describe('resetting to', () => {
      it('value', () => {
        const { formsyTextWrapper, formWrapper } = setup({
          value: 'VALUE',
        });
        const formsyForm = formWrapper.find(Form).node;
        fillInText(formsyTextWrapper, 'some text');
        formsyForm.reset();
        const formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('VALUE');
      });

      it('defaultValue', () => {
        const { formsyTextWrapper, formWrapper } = setup({
          defaultValue: 'VALUE',
        });
        const formsyForm = formWrapper.find(Form).node;
        fillInText(formsyTextWrapper, 'some text');
        formsyForm.reset();
        const formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('VALUE');
      });

      it('value + defaultValue', () => {
        const { formsyTextWrapper, formWrapper } = setup({
          value: 'VALUE',
          defaultValue: 'DEFAULT-VALUE',
        });
        const formsyForm = formWrapper.find(Form).node;
        fillInText(formsyTextWrapper, 'some text');
        formsyForm.reset();
        const formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('VALUE');
      });

      it('updated value', () => {
        const props = {
          value: 'VALUE',
        };
        const { parent, formWrapper, formsyTextWrapper } = makeTestParent(props);
        const formsyForm = formWrapper.node;
        parent.setState({ value: 'NEW VALUE' });
        fillInText(formsyTextWrapper, 'some text');
        formsyForm.reset();
        // Reset reverts to the last value that has been set.
        const formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('NEW VALUE');
      });
    });
  });
});
<commit_msg>Fix test assertion<commit_after>/* eslint-env mocha, jasmine */
/* global expect */

import React, { Component, PropTypes } from 'react';
import FormsyText from '../src/FormsyText';
import TextField from 'material-ui/TextField';
import { Simulate } from 'react-addons-test-utils';
import { mountTestForm } from './support';
import { Form } from 'formsy-react';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import { mount } from 'enzyme';

function makeChildrenFn(props) {
  const fn = () => (
    <FormsyText ref="text"
      name="text"
      validations="maxLength:10"
      validationErrors={{ maxLength: 'Text is too long' }}
      { ...props }
    />
  );
  fn.DisplayName = 'FormsyText';
  return fn;
}

const setup = (props) => {
  const childrenFn = makeChildrenFn(props);
  const formWrapper = mountTestForm(childrenFn);
  const formsyTextWrapper = formWrapper.find(FormsyText);
  return {
    formWrapper,
    formsyTextWrapper,
  };
};

class TestForm extends Component {

  static childContextTypes = {
    muiTheme: PropTypes.object.isRequired,
  };

  static propTypes = {
    children: PropTypes.node,
    defaultValue: PropTypes.string,
    value: PropTypes.string,
  }

  getChildContext() {
    return { muiTheme: getMuiTheme() };
  }

  componentWillMount() {
    const { value, defaultValue } = this.props;
    this.state = { value, defaultValue };
  }

  render() {
    const { value, defaultValue, children, ...extraProps } = { ...this.props, ...this.state };
    return (
      <Form { ...extraProps }>
        {children ? children : (
          <FormsyText ref="text" name="text"
            value={value}
            defaultValue={defaultValue}
          />
        )}
      </Form>
    );
  }
}

function makeTestParent(props) {
  const parent = mount(<TestForm {...props} />);
  const formWrapper = parent.find(Form);
  const formsyTextWrapper = parent.find(FormsyText);
  return { parent, formWrapper, formsyTextWrapper };
}

const fillInText = (wrapper, text) => {
  const inputDOM = wrapper.find('input').node;
  inputDOM.value = text;
  Simulate.change(inputDOM);
  Simulate.blur(inputDOM);
};

describe('FormsyText', () => {
  it('renders a material-ui TextField', () => {
    const { formsyTextWrapper } = setup();
    expect(formsyTextWrapper).to.have.descendants(TextField);
  });

  it('sends input to the form', () => {
    const { formsyTextWrapper, formWrapper } = setup();
    fillInText(formsyTextWrapper, 'some text');
    const formsyForm = formWrapper.find(Form).node;
    const formValues = formsyForm.getCurrentValues();
    expect(formValues.text).to.eq('some text');
  });

  it('renders validation information', () => {
    const { formsyTextWrapper, formWrapper } = setup();

    expect(formsyTextWrapper).to.not.contain.text('Text is too long');

    const formsyForm = formWrapper.find(Form).node;
    fillInText(formsyTextWrapper, 'toooooooo loooooong');
    formsyForm.validateForm();
    expect(formsyTextWrapper).to.contain.text('Text is too long');

    fillInText(formsyTextWrapper, 'just fine');
    formsyForm.validateForm();
    expect(formsyTextWrapper).to.not.contain.text('Text is too long');
  });

  describe('value properties handle', () => {
    describe('initial', () => {
      it('value', () => {
        const { formsyTextWrapper, formWrapper } = setup({
          value: 'VALUE',
        });
        const formsyForm = formWrapper.find(Form).node;
        let formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('VALUE');
        fillInText(formsyTextWrapper, 'some text');
        formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('some text');
      });

      it('defaultValue', () => {
        const { formsyTextWrapper, formWrapper } = setup({
          defaultValue: 'DEFAULT-VALUE',
        });
        const formsyForm = formWrapper.find(Form).node;
        let formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('DEFAULT-VALUE');
        fillInText(formsyTextWrapper, 'some text');
        formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('some text');
      });

      it('value + defaultValue', () => {
        const { formsyTextWrapper, formWrapper } = setup({
          value: 'VALUE',
          defaultValue: 'DEFAULT-VALUE',
        });
        const formsyForm = formWrapper.find(Form).node;
        let formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('VALUE');
        fillInText(formsyTextWrapper, 'some text');
        formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('some text');
      });

      it('propagates disabled status', () => {
        const wrapper = mount(
          <TestForm disabled={true} >
            <FormsyText
              name="text"
            />
          </TestForm>
        );

        const inputDOM = wrapper.find('input').node;
        expect(inputDOM.disabled).to.eq(true);

        // Next, we set `disabled` to false and check the DOM node updates accordingly
        wrapper.setProps({
          disabled: false,
        });
        expect(inputDOM.disabled).to.eq(false);
      });

      it('allows overriding disabled status locally', () => {
        let wrapper = mount(
          <TestForm disabled={true}>
            <FormsyText
              name="text"
              disabled={false}
            />
          </TestForm>
        );

        // Here we check we can disable a single input in a globally enabled form
        let inputDOM = wrapper.find('input').node;
        expect(inputDOM.disabled).to.eq(false);

        wrapper = mount(
          <TestForm disabled={false}>
            <FormsyText
              name="text"
              disabled={true}
            />
          </TestForm>
        );

        // Likewise, we are able to keep a specific input enabled even if the form is marked as disabled
        inputDOM = wrapper.find('input').node;
        expect(inputDOM.disabled).to.eq(true);
      });
    });

    describe('updating', () => {
      it('value', () => {
        const props = {
          value: 'VALUE',
        };
        const { parent, formWrapper, formsyTextWrapper } = makeTestParent(props);
        const formsyForm = formWrapper.node;
        parent.setState({ value: 'NEW VALUE' });
        let formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('NEW VALUE');
        fillInText(formsyTextWrapper, 'some text');
        formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('some text');
        parent.setState({ value: 'NEWER VALUE' });
        formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('NEWER VALUE');
      });

      it('defaultValue', () => {
        const props = {
          defaultValue: 'VALUE',
        };
        const { parent, formWrapper, formsyTextWrapper } = makeTestParent(props);
        const formsyForm = formWrapper.node;
        parent.setState({ defaultValue: 'NEW VALUE' });
        let formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('NEW VALUE');
        fillInText(formsyTextWrapper, 'some text');
        formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('some text');
        parent.setState({ defaultValue: 'NEWER VALUE' });
        // defaultValues does not override the typed in value.
        formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('some text');
      });

      it('calls onChange once per text update', () => {
        const calls = [];
        const { parent, formsyTextWrapper } = makeTestParent({
          onChange: (...args) => calls.push(args),
          value: 'initial',
        });

        const inputDOM = formsyTextWrapper.find('input').node;
        inputDOM.value = 'updated';
        parent.setState({ value: 'updated' });

        expect(calls.length < 3).to.eq(true);
      });
    });

    describe('resetting to', () => {
      it('value', () => {
        const { formsyTextWrapper, formWrapper } = setup({
          value: 'VALUE',
        });
        const formsyForm = formWrapper.find(Form).node;
        fillInText(formsyTextWrapper, 'some text');
        formsyForm.reset();
        const formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('VALUE');
      });

      it('defaultValue', () => {
        const { formsyTextWrapper, formWrapper } = setup({
          defaultValue: 'VALUE',
        });
        const formsyForm = formWrapper.find(Form).node;
        fillInText(formsyTextWrapper, 'some text');
        formsyForm.reset();
        const formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('VALUE');
      });

      it('value + defaultValue', () => {
        const { formsyTextWrapper, formWrapper } = setup({
          value: 'VALUE',
          defaultValue: 'DEFAULT-VALUE',
        });
        const formsyForm = formWrapper.find(Form).node;
        fillInText(formsyTextWrapper, 'some text');
        formsyForm.reset();
        const formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('VALUE');
      });

      it('updated value', () => {
        const props = {
          value: 'VALUE',
        };
        const { parent, formWrapper, formsyTextWrapper } = makeTestParent(props);
        const formsyForm = formWrapper.node;
        parent.setState({ value: 'NEW VALUE' });
        fillInText(formsyTextWrapper, 'some text');
        formsyForm.reset();
        // Reset reverts to the last value that has been set.
        const formValues = formsyForm.getCurrentValues();
        expect(formValues.text).to.eq('NEW VALUE');
      });
    });
  });
});
<|endoftext|>


<commit_before>import 'babel-polyfill'

import React from 'react'
import {render} from 'react-dom'
import {Provider} from 'react-redux'
import {Router, Route, useRouterHistory} from 'react-router'
import {createHistory} from 'history'
import {syncHistoryWithStore} from 'react-router-redux'
import {bindActionCreators} from 'redux'

import configureStore from 'src/store/configureStore'
import {loadLocalStorage} from 'src/localStorage'

import App from 'src/App'
import {
  Login,
  UserIsAuthenticated,
  UserIsNotAuthenticated,
  Purgatory,
} from 'src/auth'
import CheckSources from 'src/CheckSources'
import {StatusPage} from 'src/status'
import {HostsPage, HostPage} from 'src/hosts'
import DataExplorer from 'src/data_explorer'
import {DashboardsPage, DashboardPage} from 'src/dashboards'
import AlertsApp from 'src/alerts'
import {
  KapacitorPage,
  KapacitorRulePage,
  KapacitorRulesPage,
  KapacitorTasksPage,
  TickscriptPage,
} from 'src/kapacitor'
import {AdminChronografPage, AdminInfluxDBPage} from 'src/admin'
import {SourcePage, ManageSources} from 'src/sources'
import NotFound from 'shared/components/NotFound'

import {getLinksAsync} from 'shared/actions/links'
import {getMeAsync} from 'shared/actions/auth'

import {disablePresentationMode} from 'shared/actions/app'
import {errorThrown} from 'shared/actions/errors'

import 'src/style/chronograf.scss'

import {HEARTBEAT_INTERVAL} from 'shared/constants'

const errorsQueue = []

const rootNode = document.getElementById('react-root')

// Older method used for pre-IE 11 compatibility
const basepath = rootNode.getAttribute('data-basepath') || ''
window.basepath = basepath
const browserHistory = useRouterHistory(createHistory)({
  basename: basepath, // this is written in when available by the URL prefixer middleware
})

const store = configureStore(loadLocalStorage(errorsQueue), browserHistory)
const {dispatch} = store

browserHistory.listen(() => {
  dispatch(disablePresentationMode())
})

window.addEventListener('keyup', event => {
  const escapeKeyCode = 27
  // fallback for browsers that don't support event.key
  if (event.key === 'Escape' || event.keyCode === escapeKeyCode) {
    dispatch(disablePresentationMode())
  }
})

const history = syncHistoryWithStore(browserHistory, store)

const Root = React.createClass({
  getInitialState() {
    return {
      ready: false,
    }
  },

  async componentWillMount() {
    this.flushErrorsQueue()

    try {
      await this.getLinks()
      await this.checkAuth()
      this.setState({ready: true})
    } catch (error) {
      dispatch(errorThrown(error))
    }
  },

  getLinks: bindActionCreators(getLinksAsync, dispatch),
  getMe: bindActionCreators(getMeAsync, dispatch),

  async checkAuth() {
    try {
      await this.performHeartbeat({shouldResetMe: true})
    } catch (error) {
      dispatch(errorThrown(error))
    }
  },

  async performHeartbeat({shouldResetMe = false} = {}) {
    await this.getMe({shouldResetMe})

    setTimeout(() => {
      if (store.getState().auth.me !== null) {
        this.performHeartbeat()
      }
    }, HEARTBEAT_INTERVAL)
  },

  flushErrorsQueue() {
    if (errorsQueue.length) {
      errorsQueue.forEach(errorText => {
        dispatch(errorThrown({status: 0, auth: null}, errorText, 'warning'))
      })
    }
  },

  render() {
    return !this.state.ready
      ?

      : <Provider store={store}>
          <Router history={history}>
            <Route path="/" component={UserIsAuthenticated(CheckSources)} />
            <Route path="/login" component={UserIsNotAuthenticated(Login)} />
            <Route
              path="/purgatory"
              component={UserIsAuthenticated(Purgatory)}
            />
            <Route
              path="/sources/new"
              component={UserIsAuthenticated(SourcePage)}
            />
            <Route
              path="/sources/:sourceID"
              component={UserIsAuthenticated(App)}
            >
              <Route component={CheckSources}>
                <Route path="status" component={StatusPage} />
                <Route path="hosts" component={HostsPage} />
                <Route path="hosts/:hostID" component={HostPage} />
                <Route
                  path="chronograf/data-explorer"
                  component={DataExplorer}
                />
                <Route path="dashboards" component={DashboardsPage} />
                <Route
                  path="dashboards/:dashboardID"
                  component={DashboardPage}
                />
                <Route path="alerts" component={AlertsApp} />
                <Route path="alert-rules" component={KapacitorRulesPage} />
                <Route
                  path="alert-rules/:ruleID"
                  component={KapacitorRulePage}
                />
                <Route path="alert-rules/new" component={KapacitorRulePage} />
                <Route path="tickscript/new" component={TickscriptPage} />
                <Route path="tickscript/:ruleID" component={TickscriptPage} />
                <Route path="kapacitors/new" component={KapacitorPage} />
                <Route path="kapacitors/:id/edit" component={KapacitorPage} />
                <Route
                  path="kapacitors/:id/edit:hash"
                  component={KapacitorPage}
                />
                <Route path="kapacitor-tasks" component={KapacitorTasksPage} />
                <Route
                  path="admin-chronograf"
                  component={AdminChronografPage}
                />
                <Route path="admin-influxdb" component={AdminInfluxDBPage} />
                <Route path="manage-sources" component={ManageSources} />
                <Route path="manage-sources/new" component={SourcePage} />
                <Route path="manage-sources/:id/edit" component={SourcePage} />
              </Route>
            </Route>
            <Route path="*" component={NotFound} />
          </Router>
        </Provider>
  },
})

if (rootNode) {
  render(<Root />, rootNode)
}
<commit_msg>disable eslint for ready check<commit_after>import 'babel-polyfill'

import React from 'react'
import {render} from 'react-dom'
import {Provider} from 'react-redux'
import {Router, Route, useRouterHistory} from 'react-router'
import {createHistory} from 'history'
import {syncHistoryWithStore} from 'react-router-redux'
import {bindActionCreators} from 'redux'

import configureStore from 'src/store/configureStore'
import {loadLocalStorage} from 'src/localStorage'

import App from 'src/App'
import {
  Login,
  UserIsAuthenticated,
  UserIsNotAuthenticated,
  Purgatory,
} from 'src/auth'
import CheckSources from 'src/CheckSources'
import {StatusPage} from 'src/status'
import {HostsPage, HostPage} from 'src/hosts'
import DataExplorer from 'src/data_explorer'
import {DashboardsPage, DashboardPage} from 'src/dashboards'
import AlertsApp from 'src/alerts'
import {
  KapacitorPage,
  KapacitorRulePage,
  KapacitorRulesPage,
  KapacitorTasksPage,
  TickscriptPage,
} from 'src/kapacitor'
import {AdminChronografPage, AdminInfluxDBPage} from 'src/admin'
import {SourcePage, ManageSources} from 'src/sources'
import NotFound from 'shared/components/NotFound'

import {getLinksAsync} from 'shared/actions/links'
import {getMeAsync} from 'shared/actions/auth'

import {disablePresentationMode} from 'shared/actions/app'
import {errorThrown} from 'shared/actions/errors'

import 'src/style/chronograf.scss'

import {HEARTBEAT_INTERVAL} from 'shared/constants'

const errorsQueue = []

const rootNode = document.getElementById('react-root')

// Older method used for pre-IE 11 compatibility
const basepath = rootNode.getAttribute('data-basepath') || ''
window.basepath = basepath
const browserHistory = useRouterHistory(createHistory)({
  basename: basepath, // this is written in when available by the URL prefixer middleware
})

const store = configureStore(loadLocalStorage(errorsQueue), browserHistory)
const {dispatch} = store

browserHistory.listen(() => {
  dispatch(disablePresentationMode())
})

window.addEventListener('keyup', event => {
  const escapeKeyCode = 27
  // fallback for browsers that don't support event.key
  if (event.key === 'Escape' || event.keyCode === escapeKeyCode) {
    dispatch(disablePresentationMode())
  }
})

const history = syncHistoryWithStore(browserHistory, store)

const Root = React.createClass({
  getInitialState() {
    return {
      ready: false,
    }
  },

  async componentWillMount() {
    this.flushErrorsQueue()

    try {
      await this.getLinks()
      await this.checkAuth()
      this.setState({ready: true})
    } catch (error) {
      dispatch(errorThrown(error))
    }
  },

  getLinks: bindActionCreators(getLinksAsync, dispatch),
  getMe: bindActionCreators(getMeAsync, dispatch),

  async checkAuth() {
    try {
      await this.performHeartbeat({shouldResetMe: true})
    } catch (error) {
      dispatch(errorThrown(error))
    }
  },

  async performHeartbeat({shouldResetMe = false} = {}) {
    await this.getMe({shouldResetMe})

    setTimeout(() => {
      if (store.getState().auth.me !== null) {
        this.performHeartbeat()
      }
    }, HEARTBEAT_INTERVAL)
  },

  flushErrorsQueue() {
    if (errorsQueue.length) {
      errorsQueue.forEach(errorText => {
        dispatch(errorThrown({status: 0, auth: null}, errorText, 'warning'))
      })
    }
  },

  render() {
    return !this.state.ready // eslint-disable-line no-negated-condition
      ?

      : <Provider store={store}>
          <Router history={history}>
            <Route path="/" component={UserIsAuthenticated(CheckSources)} />
            <Route path="/login" component={UserIsNotAuthenticated(Login)} />
            <Route
              path="/purgatory"
              component={UserIsAuthenticated(Purgatory)}
            />
            <Route
              path="/sources/new"
              component={UserIsAuthenticated(SourcePage)}
            />
            <Route
              path="/sources/:sourceID"
              component={UserIsAuthenticated(App)}
            >
              <Route component={CheckSources}>
                <Route path="status" component={StatusPage} />
                <Route path="hosts" component={HostsPage} />
                <Route path="hosts/:hostID" component={HostPage} />
                <Route
                  path="chronograf/data-explorer"
                  component={DataExplorer}
                />
                <Route path="dashboards" component={DashboardsPage} />
                <Route
                  path="dashboards/:dashboardID"
                  component={DashboardPage}
                />
                <Route path="alerts" component={AlertsApp} />
                <Route path="alert-rules" component={KapacitorRulesPage} />
                <Route
                  path="alert-rules/:ruleID"
                  component={KapacitorRulePage}
                />
                <Route path="alert-rules/new" component={KapacitorRulePage} />
                <Route path="tickscript/new" component={TickscriptPage} />
                <Route path="tickscript/:ruleID" component={TickscriptPage} />
                <Route path="kapacitors/new" component={KapacitorPage} />
                <Route path="kapacitors/:id/edit" component={KapacitorPage} />
                <Route
                  path="kapacitors/:id/edit:hash"
                  component={KapacitorPage}
                />
                <Route path="kapacitor-tasks" component={KapacitorTasksPage} />
                <Route
                  path="admin-chronograf"
                  component={AdminChronografPage}
                />
                <Route path="admin-influxdb" component={AdminInfluxDBPage} />
                <Route path="manage-sources" component={ManageSources} />
                <Route path="manage-sources/new" component={SourcePage} />
                <Route path="manage-sources/:id/edit" component={SourcePage} />
              </Route>
            </Route>
            <Route path="*" component={NotFound} />
          </Router>
        </Provider>
  },
})

if (rootNode) {
  render(<Root />, rootNode)
}
<|endoftext|>


<commit_before>
import PropTypes from 'prop-types';

/**
 * Common Shapes for use on Component.propTypes.
 */
export const VariantShape = {
    id: PropTypes.string,
    name: PropTypes.string,
    description: PropTypes.string,
    rendered: PropTypes.string.isRequired,
    metadata: PropTypes.shape()
};

export const PatternShape = {
    name: PropTypes.string.isRequired,
    rendered: PropTypes.string,
    used: PropTypes.arrayOf(PropTypes.string),
    variants: PropTypes.arrayOf(PropTypes.shape(VariantShape)),
    metadata: PropTypes.shape(),
    problems: PropTypes.arrayOf(PropTypes.string)
};

export const UsedShape = {
    name: PropTypes.string.isRequired,
    id: PropTypes.string.isRequired
};<commit_msg>Remove old types file<commit_after><|endoftext|>