<commit_before>var l10n = {
  "en": {
    "unique":"Remixing is an important part of Scratch! Celebrate it in this Scratch Design Studio!\n

\n        Remix one of the projects below, and add your own ideas!
\n        https://scratch.mit.edu/projects/86370044/
\n        https://scratch.mit.edu/projects/85132566/
\n        https://scratch.mit.edu/projects/85111610/

\n\n\n        A few suggestions for your remix is to include:
\n        -More sprites: You could add your own character or prop!
\n        -Some sounds: Why not add some music or sound effects?
\n        -Different gameplay or a different story: Your remix doesn't have to be the same! Try changing it to suit your liking!
\n\n        Feel free to use art, sounds, scripts, ideas or anything from other Scratchers, but make sure to give proper credit when doing so!\n

\n\n        Don't know how to remix? Check out this tutorial!\n        https://scratch.mit.edu/projects/96160058/\n

",
    "standard":"To have your project added to this studio, please post a comment with a link. You can find a link to your project by clicking the ‘Embed’ button on the project page. The link will be directly below the Facebook logo.\n
\n        Please submit a single project made no earlier than one month before the start of this Design studio. However, you can update your project, and it'll be eligible again. If you have an older project that would fit, add some new features and feel free to submit the updated version!\n
\n        All projects must meet the community guidelines and be appropriate for all ages!\n
\n        It may take some time for your projects to be added. Please be patient, we add projects oldest to newest; no need to double post!\n

\n\n        SDS (Scratch Design Studio) is a themed studio where any Scratcher can submit a project that matches the current theme so long as it meets the requirements shown above.\n        \n        Check out this project to see how new SDS curators are selected: https://scratch.mit.edu/projects/55738732/\n        Please do not simply ask to be a curator!\n

\n\n        Do you have an idea for a future design studio? Visit the studio linked below, read the studio description, and then submit your idea in the form of a project here: http://scratch.mit.edu/studios/93627\n

\n\n        Questions about Scratch Design Studio? Check out the Scratch Wiki's article on it: http://wiki.scratch.mit.edu/wiki/SDS\n

\n\n        Check out this account for new updates on the SDS, new SDS curators and more! @SDS-Updates\n

\n\n        Credit to @st19_galla and @CrazyNimbus for the thumbnail!\n\n        <br/",
    "curators":"The SDS is curated by"
  },
  "es": {
    "translator":"Traducción por @mundofinky",
    "unique":"¡Las reinvenciones son una parte importante de Scratch! ¡Celebremos eso en este nuevo Estudio de Diseño de Scratch!\n

\n        ¡Reinventa uno de los proyectos de abajo y agrega tus propias ideas!
\n       https://scratch.mit.edu/projects/86370044/
\n        https://scratch.mit.edu/projects/85132566/
\n        https://scratch.mit.edu/projects/85111610/

\n\n\n        Unas sugerencias para tu reinvencion es incluir:
\n        -Más objetos: ¡Podrías agregar tu propio personaje!
\n        -Algunos sonidos: ¿Por qué no agregar música o efectos de sonido?
\n        -Diferente historia o juego: ¡Tu reinvención no tiene que tener lo mismo! ¡Trata de cambiarla a tu gusto!
\n\n        Siéntete libre de usar arte, sonidos, códigos, ideas o cualquier cosa de otros Scratchers, pero asegúrate de darles crédito!\n

\n\n        ¿No sabes como reinventar un proyecto! ¡Mira este tutorial! (En inglés)\n        https://scratch.mit.edu/projects/96160058/\n

",
    "standard":"Para tener tu proyecto agregado al estudio, por favor envíe un comentario con un enlace. Puedes encontrar el enlace a tu proyecto haciendo click en el botón \"Embed\" en la página de tu proyecto. El enlace estará abajo del logo de Facebook.\n
\n        Por favor publique un solo proyecto no hecho antes de un mes antes de el comienzo de este estudio de diseño. Aunque, puedes actualizar tu proyecto, y será elegible de vuelta. Si tienes un proyecto viejo que podrías agregar a este estudio, ¡agregue algunas nuevas funcionas y envíenos la version actualizada!\n
\n        Todos los proyectos deben estar de acuerdo con las reglas de la comunidad y ser apropiados para todas las edades.\n
\n        Puede que tome tiempo para que tu proyecto se agregue. Por favor sea pasiente, agregamos proyectos del más viejo al más nuevo; ¡no hay necesidad de pedirnos dos veces!\n

\n\n        EDS (Estudio de Diseño de Scratch) es un estudio en donde cualquier Scratcher puede publicar un proyecto que coincida con el tema actual su coincide con los requerimientos mencionados arriba.\n        \n        Mire este proyecto para ver cómo se seleccionan nuevos curadores del EDS: (En inglés) https://scratch.mit.edu/projects/55738732/\n        ¡Por favor no simplemente pregunte ser un curador!\n

\n\n        ¿Tienes una idea para un estudio futuro? Visite el enlace de abajo, lea la descripción del estudio, y luego envpia tu idea en forma de un proyecto aquí: http://scratch.mit.edu/studios/93627\n

\n\n        ¿Preguntas acerca del Estudio de Diseño de Scratch? Mire el articulo de la Wiki de Scratch: (En inglés) http://wiki.scratch.mit.edu/wiki/SDS\n

\n\n        Mire esta cuenta para ver nuevas actualizaciones en el EDS, nuevos curadores del EDS y más: (En inglés) @SDS-Updates\n

\n\n        Crédito a @st19_galla y a @CrazyNimbus por la imagen de este estudio.\n\n        <br/",
    "curators":"Los curadores del EDS son"
  },
  "fr": {
    "translator":"nobody.. yet",
    "unique":"french description here",
    "standard":"french filler text",
    "curators":"Le ACS est organisé par"
  },
  "de": {
    "translator":"Die Übersetzung von LiFayTheGoblin",
    "unique":"german description here",
    "standard":"Um dein Projekt dem Studio hinzuzufügen, poste bitte einen Kommentar mit dem entsprechenden Link. Du kannst den Link zu deinem Projekt finden, indem du auf der Projektseite auf 'Einbinden' klickst. Der link ist direkt unter dem Facebook-Logo.\n
\n        Reiche bitte nur ein Projekt, das nicht älter als 1 Monat ist, ein. Du kannst aber ein älteres Projekt updaten! Wenn du also ein älteres Projekt hast, das passen würde, füge einige neue Features hinzu und reiche es ein.\n
\n        Alle Projekte müssen die Community Guidelines befolgen und für alle Altersstufen angemessen sein.\n
\n        Es kann einige Zeit dauern, bis dein Projekt hinzugefügt wird. Wir bitten um Geduld - du musst den Link nicht erneut posten!\n

\n\n        SDS (Scratch Design Studio) ist ein Studio, bei dem jeder Scratcher ein Projekt, das zum aktuellen Thema passt und alle Bedingungen erfüllt, einreichen kann.\n        \n        Schau dir dieses Projekt an, um zu erfahren, wie neue SDS Kuratoren ausgesucht werden (en): https://scratch.mit.edu/projects/55738732/\n        Bitte frag nicht einfach so, ob du Kurator werden kannst!\n

\n\n        Hast du eine Idee für ein zukünftiges Design Studio? Besuche das unten verlinkte Studio, lies die Studiobeschreibung (en) und reiche dann deine Idee in der Form eines Scratch Projektes ein: http://scratch.mit.edu/studios/93627\n

\n\n        Hast du eine Frage über das Scratch Design Studio? Schau dir den Wiki-Artikel darüber an: http://scratch-dach.info/wiki/Scratch_Design_Studio\n

\n\n        Dieser Benutzer informiert über SDS-Updates, neue Kuratoren und mehr (en)! @SDS-Updates\n

\n\n        Danke an @st19_galla und @CrazyNimbus für das Studiobild!\n\n        <br/",
    "curators":"Die Kuratoren des SDS sind"
  }
}
<commit_msg>French Translation Part 1<commit_after>var l10n = {
  "en": {
    "unique":"Remixing is an important part of Scratch! Celebrate it in this Scratch Design Studio!\n

\n        Remix one of the projects below, and add your own ideas!
\n        https://scratch.mit.edu/projects/86370044/
\n        https://scratch.mit.edu/projects/85132566/
\n        https://scratch.mit.edu/projects/85111610/

\n\n\n        A few suggestions for your remix is to include:
\n        -More sprites: You could add your own character or prop!
\n        -Some sounds: Why not add some music or sound effects?
\n        -Different gameplay or a different story: Your remix doesn't have to be the same! Try changing it to suit your liking!
\n\n        Feel free to use art, sounds, scripts, ideas or anything from other Scratchers, but make sure to give proper credit when doing so!\n

\n\n        Don't know how to remix? Check out this tutorial!\n        https://scratch.mit.edu/projects/96160058/\n

",
    "standard":"To have your project added to this studio, please post a comment with a link. You can find a link to your project by clicking the ‘Embed’ button on the project page. The link will be directly below the Facebook logo.\n
\n        Please submit a single project made no earlier than one month before the start of this Design studio. However, you can update your project, and it'll be eligible again. If you have an older project that would fit, add some new features and feel free to submit the updated version!\n
\n        All projects must meet the community guidelines and be appropriate for all ages!\n
\n        It may take some time for your projects to be added. Please be patient, we add projects oldest to newest; no need to double post!\n

\n\n        SDS (Scratch Design Studio) is a themed studio where any Scratcher can submit a project that matches the current theme so long as it meets the requirements shown above.\n        \n        Check out this project to see how new SDS curators are selected: https://scratch.mit.edu/projects/55738732/\n        Please do not simply ask to be a curator!\n

\n\n        Do you have an idea for a future design studio? Visit the studio linked below, read the studio description, and then submit your idea in the form of a project here: http://scratch.mit.edu/studios/93627\n

\n\n        Questions about Scratch Design Studio? Check out the Scratch Wiki's article on it: http://wiki.scratch.mit.edu/wiki/SDS\n

\n\n        Check out this account for new updates on the SDS, new SDS curators and more! @SDS-Updates\n

\n\n        Credit to @st19_galla and @CrazyNimbus for the thumbnail!\n\n        <br/",
    "curators":"The SDS is curated by"
  },
  "es": {
    "translator":"Traducción por @mundofinky",
    "unique":"¡Las reinvenciones son una parte importante de Scratch! ¡Celebremos eso en este nuevo Estudio de Diseño de Scratch!\n

\n        ¡Reinventa uno de los proyectos de abajo y agrega tus propias ideas!
\n       https://scratch.mit.edu/projects/86370044/
\n        https://scratch.mit.edu/projects/85132566/
\n        https://scratch.mit.edu/projects/85111610/

\n\n\n        Unas sugerencias para tu reinvencion es incluir:
\n        -Más objetos: ¡Podrías agregar tu propio personaje!
\n        -Algunos sonidos: ¿Por qué no agregar música o efectos de sonido?
\n        -Diferente historia o juego: ¡Tu reinvención no tiene que tener lo mismo! ¡Trata de cambiarla a tu gusto!
\n\n        Siéntete libre de usar arte, sonidos, códigos, ideas o cualquier cosa de otros Scratchers, pero asegúrate de darles crédito!\n

\n\n        ¿No sabes como reinventar un proyecto! ¡Mira este tutorial! (En inglés)\n        https://scratch.mit.edu/projects/96160058/\n

",
    "standard":"Para tener tu proyecto agregado al estudio, por favor envíe un comentario con un enlace. Puedes encontrar el enlace a tu proyecto haciendo click en el botón \"Embed\" en la página de tu proyecto. El enlace estará abajo del logo de Facebook.\n
\n        Por favor publique un solo proyecto no hecho antes de un mes antes de el comienzo de este estudio de diseño. Aunque, puedes actualizar tu proyecto, y será elegible de vuelta. Si tienes un proyecto viejo que podrías agregar a este estudio, ¡agregue algunas nuevas funcionas y envíenos la version actualizada!\n
\n        Todos los proyectos deben estar de acuerdo con las reglas de la comunidad y ser apropiados para todas las edades.\n
\n        Puede que tome tiempo para que tu proyecto se agregue. Por favor sea pasiente, agregamos proyectos del más viejo al más nuevo; ¡no hay necesidad de pedirnos dos veces!\n

\n\n        EDS (Estudio de Diseño de Scratch) es un estudio en donde cualquier Scratcher puede publicar un proyecto que coincida con el tema actual su coincide con los requerimientos mencionados arriba.\n        \n        Mire este proyecto para ver cómo se seleccionan nuevos curadores del EDS: (En inglés) https://scratch.mit.edu/projects/55738732/\n        ¡Por favor no simplemente pregunte ser un curador!\n

\n\n        ¿Tienes una idea para un estudio futuro? Visite el enlace de abajo, lea la descripción del estudio, y luego envpia tu idea en forma de un proyecto aquí: http://scratch.mit.edu/studios/93627\n

\n\n        ¿Preguntas acerca del Estudio de Diseño de Scratch? Mire el articulo de la Wiki de Scratch: (En inglés) http://wiki.scratch.mit.edu/wiki/SDS\n

\n\n        Mire esta cuenta para ver nuevas actualizaciones en el EDS, nuevos curadores del EDS y más: (En inglés) @SDS-Updates\n

\n\n        Crédito a @st19_galla y a @CrazyNimbus por la imagen de este estudio.\n\n        <br/",
    "curators":"Los curadores del EDS son"
  },
  "fr": {
    "translator":"Traduction par @Smrman",
    "unique":"Le remix de projets est fait partie intégrante de Scratch! Célébrons-le dans ce Studio de Design Scratch!\n

\n        Remixe un des projets ci-dessous, ajoute tes propres idées!
\n        https://scratch.mit.edu/projects/86370044/
\n        https://scratch.mit.edu/projects/85132566/
\n        https://scratch.mit.edu/projects/85111610/

\n\n\n        Voici quelques suggestions que ton remix peut comporter:
\n        - Ajoute plus de lutins: Tu peux ajouter ton propre style ou tes propres détails.
\n        - Des sons: Pourquoi ne pas ajouter un peu de musique?
\n        - Un gameplay différent ou une histoire différente: Vos remixs ne doivent pas être les mêmes! Essaye de le personnaliser pour qu'il soit comme tu l'aimes.
\n\n        Tu es libre d'utiliser les images, les sons, les scripts et les idées des autres Scratchers mais, si tu le fais, fais bien attention de ne pas oublier de donner le crédit au Scratcher concerné.\n

\n\n        Tu ne sais pas comment remixer un projet? Regarde ce tutoriel!\n        https://scratch.mit.edu/projects/96160058/ (en anglais) \n

",
    "standard":"french filler text",
    "curators":"Le ACS est organisé par"
  },
  "de": {
    "translator":"Die Übersetzung von LiFayTheGoblin",
    "unique":"german description here",
    "standard":"Um dein Projekt dem Studio hinzuzufügen, poste bitte einen Kommentar mit dem entsprechenden Link. Du kannst den Link zu deinem Projekt finden, indem du auf der Projektseite auf 'Einbinden' klickst. Der link ist direkt unter dem Facebook-Logo.\n
\n        Reiche bitte nur ein Projekt, das nicht älter als 1 Monat ist, ein. Du kannst aber ein älteres Projekt updaten! Wenn du also ein älteres Projekt hast, das passen würde, füge einige neue Features hinzu und reiche es ein.\n
\n        Alle Projekte müssen die Community Guidelines befolgen und für alle Altersstufen angemessen sein.\n
\n        Es kann einige Zeit dauern, bis dein Projekt hinzugefügt wird. Wir bitten um Geduld - du musst den Link nicht erneut posten!\n

\n\n        SDS (Scratch Design Studio) ist ein Studio, bei dem jeder Scratcher ein Projekt, das zum aktuellen Thema passt und alle Bedingungen erfüllt, einreichen kann.\n        \n        Schau dir dieses Projekt an, um zu erfahren, wie neue SDS Kuratoren ausgesucht werden (en): https://scratch.mit.edu/projects/55738732/\n        Bitte frag nicht einfach so, ob du Kurator werden kannst!\n

\n\n        Hast du eine Idee für ein zukünftiges Design Studio? Besuche das unten verlinkte Studio, lies die Studiobeschreibung (en) und reiche dann deine Idee in der Form eines Scratch Projektes ein: http://scratch.mit.edu/studios/93627\n

\n\n        Hast du eine Frage über das Scratch Design Studio? Schau dir den Wiki-Artikel darüber an: http://scratch-dach.info/wiki/Scratch_Design_Studio\n

\n\n        Dieser Benutzer informiert über SDS-Updates, neue Kuratoren und mehr (en)! @SDS-Updates\n

\n\n        Danke an @st19_galla und @CrazyNimbus für das Studiobild!\n\n        <br/",
    "curators":"Die Kuratoren des SDS sind"
  }
}
<|endoftext|>


<commit_before>Polymer({
  is: 'grouped-composite-chart',
  draw: function() {
    this.debounce('draw-debounce', () => {
      let xIndex = this.getInputsProperty('x');
      let yIndices = this.getInputsProperty('y');
      let yLine = this.getInputsProperty('z');
      let z = this.setLegendColor.bind(this);
      this.resize();
      // requireed indices not selected
      if (xIndex === -1 || !yIndices || yIndices.length < 1 || !this.source || this.source.length < 1) {
        console.warn('Fill all required inputs using drag and drop');
        return false;
      }

      let headers = this.externals.map(e => {
        return e.key;
      });

      // cloning the source to keep it intact
      let _src = JSON.parse(JSON.stringify(this.source));

      if (this.parentG) {
        this.parentG.html("");
      }

      let conf = this._conf(); // generate config
      let _isGrouped = false; // disable groupby z-input

      let myGroup = PolymerD3
        .groupingBehavior
        .group_by(yIndices, xIndex, yIndices,
          headers, conf.chartType, _isGrouped
        );
      let nChartConfig = this.chartConfig(conf, _src, myGroup.process);

      let stackData = myGroup.getStack();

      nChartConfig.stackDataLength = stackData.length;

      let translations = this._processors(nChartConfig);

      let layer = this.parentG.selectAll('.layer')
        .data(stackData)
        .enter().append('g')
        .attr('transform', translations.translate)
        .attr('class', 'layer')
        .style('fill', d => {
          // Logic to generate legends initialy
          let color = z(d);
          let keyPresent = false;
          this.legendSettings.colors.forEach((c) => {
            if (c.label == d.key) {
              color = c.color;
              keyPresent = true;
            }
          });
          // Create new entry if legend isn't present
          // TO do: remove &&d.key =>  something's wrong with generate stackData meathod
          // d.key comes as undefined check `PolymerD3.groupingBehavior`
          if (!keyPresent && d.key) {
            this.legendSettings.colors.push({
              color: color,
              label: d.key
            });
          }
          return color;
        })
        .attr('class', 'stroked-elem') // to set stroke
        .attr('data-legend', function(d) {
          return d.key;
        });
      // this.attachLegend(this.parentG);

      let rects = layer.selectAll('rect')
        .data(function(d) {
          return d.values;
        })
        .enter().append('rect')
        .attr('x', translations.rectX)
        .attr('y', translations.rectY)
        .attr('height', translations.rectHeight)
        .attr('width', translations.barWidth)
        // .attr('data-legend', translations.legendF)
        .attr('class', translations.classF);
      // to draw line chart
      if (yLine && yLine.length) {

        let lineData = this.source.map(row => ({
          x: row[xIndex],
          y: row[yLine[0]]
        }));

        let x = d3.scale.ordinal()
          .rangeRoundBands([0, this.chartWidth]);

        x.domain(lineData.map(d => d.x));

        let guide = d3.svg.line()
          .x(d => x(d.x))
          .y(d => yLineScale(d.y))
          .interpolate('basis');

        let yLineScale = d3.scale.linear()
          .domain([0, d3.max(lineData, row => row.y)])
          .range([this.chartHeight, 0]);

        let yAxis2 = d3.svg.axis()
          .scale(yLineScale)
          .orient('right');

        let line = this.parentG.append('path')
          .datum(lineData)
          .attr('d', guide)
          .attr('class', 'line');

        this.parentG.append('g')
          .attr('class', 'y-axis')
          .attr('transform', 'translate(' + [this.chartWidth, 0] + ')')
          .call(yAxis2)
          .append('text')
          .attr('transform', 'rotate(-90)')
          .attr('y', 4)
          .attr('dy', '-.71em')
          .style('text-anchor', 'end');
      }

      let htmlCallback = d => { // retained as arrow function to access `this.inputs[]`
        let str = '
' +
          '
' +
          '' + this.inputs[0].displayName + ':	' +
          '' + d.x + '	' +
          '
' +
          '
' +
          '' + this.inputs[1].displayName + ':	' +
          '' + d.y + '	' +
          '
' +
          '
';
        return str;
      };
      this.attachToolTip(this.parentG, rects, 'vertalBars', htmlCallback);

      this.attachLegend(this.parentG);
    }, 500);
  },

  properties: {
    title: '',
    inputs: {
      notify: true,
      type: Array,
      value: () => {
        return [{
          input: 'x',
          txt: 'Pick Dimension',
          selectedValue: [],
          scaleType: '',
          format: '',
          selectedObjs: [],
          uitype: 'single-value',
          displayName: 'myXAxis',
          maxSelectableValues: 1
        }, {
          input: 'y',
          txt: 'Pick Measures',
          selectedValue: [],
          format: '',
          scaleType: '',
          selectedObjs: [],
          uitype: 'multi-value',
          displayName: 'myYAxis',
          maxSelectableValues: 2,
          supportedType: ''
        }, {
          input: 'z',
          txt: 'Pick Z',
          selectedValue: [],
          format: '',
          scaleType: '',
          selectedObjs: [],
          uitype: 'multi-value',
          displayName: 'myZAxis',
          maxSelectableValues: 2,
          supportedType: ''
        }];
      }
    },
    settings: {
      notify: true,
      type: Object,
      value: () => {
        return [];
      }
    },
    chartType: {
      type: Object,
      value: () => {
        return [];
      }
    },
    hideSettings: true,
    source: Array,
    external: Array,
    chart: Object,
    dataMutated: false,
    isStacked: {
      type: Boolean,
      value: true
    },
    configurator: {
      type: Object,
      value: function() {
        return {};
      }
    }
  },

  behaviors: [
    PolymerD3.chartBehavior,
    PolymerD3.chartConfigCbBehavior
  ],

  _conf: function() {
    let xIndex = this.getInputsProperty('x');
    let yIndices = this.getInputsProperty('y');
    let xObj = this.getInputsPropertyObj('x');
    let yObj = this.getInputsPropertyObj('y');
    let zGroup = this.getInputsProperty('z');

    let forcetToZero = true;

    // if (yIndices.length > 1 || zGroup.length) {
      // forcetToZero = true;
    // }

    return {
      stackIndex: xIndex,
      chartType: 'stack', //stack,group,diff,waterfall
      containsHeader: false,
      xheader: [xIndex],
      yOrign: 0,
      yheader: yIndices,
      width: this.chartWidth,
      height: this.chartHeight,
      xFormat: xObj.selectedObjs[0].type,
      yFormat: yObj.selectedObjs[0].type,
      xAlign: 'bottom',
      yAlign: 'left',
      xaxisType: 'ordinal',
      yaxisType: 'linear',
      parentG: this.parentG,
      forcetToZero: forcetToZero
    };
  },
  _processors: function(nChartConfig) {
    return {
      translate: (d, i) => {
        return 'translate(' + i * nChartConfig.getBarWidth() / nChartConfig.stackDataLength + ',0)';
      },
      barWidth: () => {
        return nChartConfig.getBarWidth() / nChartConfig.stackDataLength - 1;
      },
      rectX: (d) => {
        return nChartConfig.getX(d[0]);
      },
      rectY: (d) => {
        return nChartConfig.getY(d[1]);
      },
      rectHeight: (d) => {
        return nChartConfig.getBarHeight(d[1]);
      },
      legendF: (d, i, j) => {
        // console.log('d:' + d + ' i:' + i + ' j:' + j);
      }
    }
  }

});
<commit_msg>Both axes share the same scale<commit_after>Polymer({
  is: 'grouped-composite-chart',
  draw: function() {
    this.debounce('draw-debounce', () => {
      let xIndex = this.getInputsProperty('x');
      let yIndices = this.getInputsProperty('y');
      let yLine = this.getInputsProperty('z');
      let z = this.setLegendColor.bind(this);
      this.resize();
      // requireed indices not selected
      if (xIndex === -1 || !yIndices || yIndices.length < 1 || !this.source || this.source.length < 1) {
        console.warn('Fill all required inputs using drag and drop');
        return false;
      }

      let headers = this.externals.map(e => {
        return e.key;
      });

      // cloning the source to keep it intact
      let _src = JSON.parse(JSON.stringify(this.source));

      if (this.parentG) {
        this.parentG.html("");
      }

      let conf = this._conf(); // generate config
      let _isGrouped = false; // disable groupby z-input

      let myGroup = PolymerD3
        .groupingBehavior
        .group_by(yIndices, xIndex, yIndices,
          headers, conf.chartType, _isGrouped
        );
      let nChartConfig = this.chartConfig(conf, _src, myGroup.process);

      let stackData = myGroup.getStack();

      nChartConfig.stackDataLength = stackData.length;

      let translations = this._processors(nChartConfig);

      let layer = this.parentG.selectAll('.layer')
        .data(stackData)
        .enter().append('g')
        .attr('transform', translations.translate)
        .attr('class', 'layer')
        .style('fill', d => {
          // Logic to generate legends initialy
          let color = z(d);
          let keyPresent = false;
          this.legendSettings.colors.forEach((c) => {
            if (c.label == d.key) {
              color = c.color;
              keyPresent = true;
            }
          });
          // Create new entry if legend isn't present
          // TO do: remove &&d.key =>  something's wrong with generate stackData meathod
          // d.key comes as undefined check `PolymerD3.groupingBehavior`
          if (!keyPresent && d.key) {
            this.legendSettings.colors.push({
              color: color,
              label: d.key
            });
          }
          return color;
        })
        .attr('class', 'stroked-elem') // to set stroke
        .attr('data-legend', function(d) {
          return d.key;
        });
      // this.attachLegend(this.parentG);

      let rects = layer.selectAll('rect')
        .data(function(d) {
          return d.values;
        })
        .enter().append('rect')
        .attr('x', translations.rectX)
        .attr('y', translations.rectY)
        .attr('height', translations.rectHeight)
        .attr('width', translations.barWidth)
        // .attr('data-legend', translations.legendF)
        .attr('class', translations.classF);
      // to draw line chart
      if (yLine && yLine.length) {

        let lineData = this.source.map(row => ({
          x: row[xIndex],
          y: row[yLine[0]]
        }));

        let x = d3.scale.ordinal()
          .rangeRoundBands([0, this.chartWidth]);

        x.domain(lineData.map(d => d.x));

        let guide = d3.svg.line()
          .x(d => x(d.x))
          .y(d => yLineScale(d.y))
          .interpolate('basis');

        let yLineScale = conf.yAxisConf.scale;

        let yAxis2 = d3.svg.axis()
          .scale(yLineScale)
          .orient('right');

        let line = this.parentG.append('path')
          .datum(lineData)
          .attr('d', guide)
          .attr('class', 'line');

        this.parentG.append('g')
          .attr('class', 'y-axis')
          .attr('transform', 'translate(' + [this.chartWidth, 0] + ')')
          .call(yAxis2)
          .append('text')
          .attr('transform', 'rotate(-90)')
          .attr('y', 4)
          .attr('dy', '-.71em')
          .style('text-anchor', 'end');
      }

      let htmlCallback = d => { // retained as arrow function to access `this.inputs[]`
        let str = '
' +
          '
' +
          '' + this.inputs[0].displayName + ':	' +
          '' + d.x + '	' +
          '
' +
          '
' +
          '' + this.inputs[1].displayName + ':	' +
          '' + d.y + '	' +
          '
' +
          '
';
        return str;
      };
      this.attachToolTip(this.parentG, rects, 'vertalBars', htmlCallback);

      this.attachLegend(this.parentG);
    }, 500);
  },

  properties: {
    title: '',
    inputs: {
      notify: true,
      type: Array,
      value: () => {
        return [{
          input: 'x',
          txt: 'Pick Dimension',
          selectedValue: [],
          scaleType: '',
          format: '',
          selectedObjs: [],
          uitype: 'single-value',
          displayName: 'myXAxis',
          maxSelectableValues: 1
        }, {
          input: 'y',
          txt: 'Pick Measures',
          selectedValue: [],
          format: '',
          scaleType: '',
          selectedObjs: [],
          uitype: 'multi-value',
          displayName: 'myYAxis',
          maxSelectableValues: 2,
          supportedType: ''
        }, {
          input: 'z',
          txt: 'Pick Z',
          selectedValue: [],
          format: '',
          scaleType: '',
          selectedObjs: [],
          uitype: 'multi-value',
          displayName: 'myZAxis',
          maxSelectableValues: 2,
          supportedType: ''
        }];
      }
    },
    settings: {
      notify: true,
      type: Object,
      value: () => {
        return [];
      }
    },
    chartType: {
      type: Object,
      value: () => {
        return [];
      }
    },
    hideSettings: true,
    source: Array,
    external: Array,
    chart: Object,
    dataMutated: false,
    isStacked: {
      type: Boolean,
      value: true
    },
    configurator: {
      type: Object,
      value: function() {
        return {};
      }
    }
  },

  behaviors: [
    PolymerD3.chartBehavior,
    PolymerD3.chartConfigCbBehavior
  ],

  _conf: function() {
    let xIndex = this.getInputsProperty('x');
    let yIndices = this.getInputsProperty('y');
    let xObj = this.getInputsPropertyObj('x');
    let yObj = this.getInputsPropertyObj('y');
    let zGroup = this.getInputsProperty('z');

    let forcetToZero = true;

    // if (yIndices.length > 1 || zGroup.length) {
      // forcetToZero = true;
    // }

    return {
      stackIndex: xIndex,
      chartType: 'stack', //stack,group,diff,waterfall
      containsHeader: false,
      xheader: [xIndex],
      yOrign: 0,
      yheader: yIndices,
      width: this.chartWidth,
      height: this.chartHeight,
      xFormat: xObj.selectedObjs[0].type,
      yFormat: yObj.selectedObjs[0].type,
      xAlign: 'bottom',
      yAlign: 'left',
      xaxisType: 'ordinal',
      yaxisType: 'linear',
      parentG: this.parentG,
      forcetToZero: forcetToZero
    };
  },
  _processors: function(nChartConfig) {
    return {
      translate: (d, i) => {
        return 'translate(' + i * nChartConfig.getBarWidth() / nChartConfig.stackDataLength + ',0)';
      },
      barWidth: () => {
        return nChartConfig.getBarWidth() / nChartConfig.stackDataLength - 1;
      },
      rectX: (d) => {
        return nChartConfig.getX(d[0]);
      },
      rectY: (d) => {
        return nChartConfig.getY(d[1]);
      },
      rectHeight: (d) => {
        return nChartConfig.getBarHeight(d[1]);
      },
      legendF: (d, i, j) => {
        // console.log('d:' + d + ' i:' + i + ' j:' + j);
      }
    }
  }

});
<|endoftext|>


<commit_before>YUI.add('aui-datatable-tests', function(Y) {

    var suite = new Y.Test.Suite('aui-datatable');

    var data = [
        {
            active: 'no',
            address: '3271 Another Ave',
            amount: 3,
            city: 'New York',
            colors: ['red', 'blue'],
            date: '2013-01-01',
            fruit: ['apple'],
            name: 'Joan B. Jones',
            state: 'AL'
        },
        {
            active: 'maybe',
            address: '9996 Random Road',
            amount: 0,
            city: 'Los Angeles',
            colors: ['green'],
            date: '2013-01-01',
            fruit: ['cherry'],
            name: 'Bob C. Uncle',
            state: 'CA'
        },
        {
            active: 'yes',
            address: '1623 Some Street',
            amount: 5,
            city: 'San Francisco',
            colors: ['red'],
            date: '',
            fruit: ['cherry'],
            name: 'John D. Smith',
            state: 'CA'
        },
        {
            active: 'no',
            address: '3217 Another Ave',
            amount: 3,
            city: 'New York',
            colors: ['red', 'blue'],
            date: '2013-01-06',
            fruit: ['apple', 'cherry'],
            name: 'Joan E. Jones',
            state: 'KY'
        }
    ];

    new Y.DataTable({
        boundingBox: '#simple',
        columns: [
            {
                editor: new Y.TextAreaCellEditor({
                    on: {
                        cancel: function(event) {
                            console.log('cancel', event);
                        },
                        save: function(event) {
                            console.log('save', event.newVal);
                        }
                    },
                    validator: {
                        rules: {
                            value: {
                                required: true
                            }
                        }
                    }
                }),
                key: 'name',
                sortable: true
            },
            {
                editor: new Y.TextAreaCellEditor(),
                key: 'address'
            },
            {
                editor: new Y.TextAreaCellEditor(),
                key: 'city'
            },
            {
                editor: new Y.DropDownCellEditor({
                    editable: true,
                    options: ['AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FL', 'GA', 'HI', 'ID',
                        'IL', 'IN', 'IA', 'KS', 'KY', 'LA']
                }),
                key: 'state'
            },
            'amount',
            {
                editor: new Y.RadioCellEditor({
                    editable: true,
                    options: {
                        yes: 'Yes',
                        no: 'No',
                        maybe: 'Maybe'
                    }
                }),
                key: 'active'
            },
            {
                editor: new Y.CheckboxCellEditor({
                    editable: true,
                    multiple: true,
                    options: {
                        red: 'Red',
                        green: 'Green',
                        blue: 'Blue'
                    }
                }),
                key: 'colors'
            },
            {
                editor: new Y.DropDownCellEditor({
                    editable: true,
                    multiple: true,
                    options: {
                        apple: 'Apple',
                        banana: 'Banana',
                        cherry: 'Cherry',
                        kiwi: 'Kiwi'
                    }
                }),
                key: 'fruit',
                sortable: true
            },
            {
                editor: new Y.DateCellEditor({
                    calendar: {
                        selectionMode: 'multiple',
                        showNextMonth: true,
                        showPrevMonth: true,
                        width: '400px'
                    }
                }),
                key: 'date',
                sortable: true
            }
        ],
        data: data,
        editEvent: 'dblclick',
        plugins: [
            {
                fn: Y.Plugin.DataTableHighlight
            }
        ]
    }).render();

    function assertHighlightPosition(tableData) {
        var lowerXLimit,
            lowerYLimit,
            overlayActiveBorderWidth,
            overlayActiveBottomWidth,
            overlayActiveChildren,
            overlayActiveLeftHeight,
            overlayActiveNode,
            overlayActiveRightHeight,
            overlayActiveTopWidth,
            overlaySelectionNode,
            tableDataHeight,
            tableDataWidth,
            upperXLimit,
            upperYLimit;

        overlayActiveNode = Y.one('.table-highlight-overlay-active');
        overlayActiveChildren = overlayActiveNode.get('children');
        overlaySelectionNode = overlayActiveNode ? overlayActiveNode.next('.table-highlight-overlay') : null;

        lowerXLimit = tableData.getX() >= (overlayActiveNode.getX() - 1);
        lowerYLimit = tableData.getY() >= (overlayActiveNode.getY() - 1);

        overlayActiveBorderWidth = overlayActiveChildren.item(0).get('offsetHeight');
        overlayActiveBottomWidth = overlayActiveChildren.item(2).get('offsetWidth');

        overlayActiveLeftHeight = overlayActiveChildren.item(3).get('offsetHeight') + overlayActiveBorderWidth;
        overlayActiveRightHeight = overlayActiveChildren.item(1).get('offsetHeight') + overlayActiveBorderWidth;

        overlayActiveTopWidth = overlayActiveChildren.item(0).get('offsetWidth');

        tableDataHeight = tableData.get('offsetHeight');
        tableDataWidth = tableData.get('offsetWidth');

        upperXLimit = tableData.getX() <= (overlayActiveNode.getX() + 1);
        upperYLimit = tableData.getY() <= (overlayActiveNode.getY() + 1);

        Y.Assert.isTrue(
            (lowerXLimit && upperXLimit),
            'X Position of 	 and highlight are not the similar.');

        Y.Assert.isTrue(
            (lowerYLimit && upperYLimit),
            'Y Position of 	 and highlight are not the similar.');

        Y.Assert.areSame(
            tableDataWidth,
            overlayActiveBottomWidth,
            'Hightlight bottom border width ' + overlayActiveBottomWidth + ' is not same width as table data ' +
            tableDataWidth + '.');

        Y.Assert.areSame(
            tableDataWidth,
            overlayActiveTopWidth,
            'Hightlight top border width ' + overlayActiveTopWidth + ' is not same width as table data ' +
            tableDataWidth + '.');

        Y.Assert.areSame(
            tableDataHeight,
            overlayActiveLeftHeight,
            'Hightlight left border height ' + overlayActiveLeftHeight + ' is not same height as table data ' +
            tableDataHeight + '.');

        Y.Assert.areSame(
            tableDataHeight,
            overlayActiveRightHeight,
            'Hightlight right border height ' + overlayActiveRightHeight + ' is not same height as table data ' +
            tableDataHeight + '.');
    }

    suite.add(new Y.Test.Case({
        name: 'Datatable Highlight',
        'table-cell should be highlighted on click': function() {
            var test = this,
                tableData;

            tableData = Y.one('tr.table-odd td.table-col-amount');

            tableData.once('mousedown', function(event) {
                setTimeout(function() {
                    test.resume(function() {
                        assertHighlightPosition(event.currentTarget);
                    });
                }, 800);
            });

            setTimeout(function() {
                tableData.simulate('mousedown');
                tableData.simulate('mouseup');
            }, 0);

            test.wait(1000);
        },

        'table-cell should still be highlighted when table is scrolled horizontally': function() {
            var test = this,
                datatableContainer,
                datatableContent,
                tableData;

            datatableContainer = Y.one('#simple');
            datatableContent = datatableContainer.one('.table-content');
            tableData = Y.one('tr.table-odd td.table-col-amount');

            datatableContainer.setStyle('width', '300px');
            datatableContent.setStyle('overflow', 'auto');

            tableData.once('mousedown', function(event) {
                setTimeout(function() {
                    test.resume(function() {
                        assertHighlightPosition(event.currentTarget);
                    });
                }, 800);
            });

            setTimeout(function() {
                tableData.simulate('mousedown');
                tableData.simulate('mouseup');
                datatableContent.set('scrollLeft', 200);
            }, 0);

            test.wait(1000);
        }
    }));

    suite.add(new Y.Test.Case({
        name: 'Datatable',

        init: function() {
            var data = [
                {
                    active: 'no',
                    address: '3271 Another Ave',
                    amount: 3,
                    city: 'New York',
                    colors: ['red','blue'],
                    date: '2013-01-01',
                    fruit: ['apple'],
                    name: 'Joan B. Jones',
                    state: 'AL'
                },
                {
                    active: 'maybe',
                    address: '9996 Random Road',
                    amount: 0,
                    city: 'Los Angeles',
                    colors: ['green'],
                    date: '2013-01-01',
                    fruit: ['cherry'],
                    name: 'Bob C. Uncle',
                    state: 'CA'
                },
                {
                    active: 'yes',
                    address: '1623 Some Street',
                    amount: 5,
                    city: 'San Francisco',
                    colors: ['red'],
                    date: '',
                    fruit: ['cherry'],
                    name: 'John D. Smith',
                    state: 'CA'
                },
                {
                    active: 'no',
                    address: '3217 Another Ave',
                    amount: 3,
                    city: 'New York',
                    colors: ['red','blue'],
                    date: '2013-01-06',
                    fruit: ['apple','cherry'],
                    name: 'Joan E. Jones',
                    state: 'KY'
                }
            ];

            this._dataTable = new Y.DataTable({
                cssClass: 'table-striped',
                boundingBox: '#datatable',
                columns: [
                    {
                        key: 'name',
                        sortable: true,
                        editor: new Y.TextAreaCellEditor({
                            on: {
                                save: function(event) {
                                    console.log('save', event.newVal);
                                },
                                cancel: function(event) {
                                    console.log('cancel', event);
                                }
                            },
                            validator: {
                                rules: {
                                    value: {
                                        required: true
                                    }
                                }
                            }
                        })
                    },
                    {
                        key: 'address',
                        editor: new Y.TextAreaCellEditor()
                    },
                    {
                        key: 'city',
                        editor: new Y.TextAreaCellEditor()
                    },
                    {
                        key: 'state',
                        editor: new Y.DropDownCellEditor({
                            editable: true,
                            options: ['AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FL', 'GA', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA']
                        })
                    },
                    'amount',
                    {
                        key:'active',
                        editor: new Y.RadioCellEditor({
                            editable: true,
                            options: {
                                yes: 'Yes',
                                no: 'No',
                                maybe: 'Maybe'
                            }
                        })
                    },
                    {
                        key:'colors',
                        editor: new Y.CheckboxCellEditor({
                            editable: true,
                            multiple: true,
                            options: {
                                red: 'Red',
                                green: 'Green',
                                blue: 'Blue'
                            }
                        })
                    },
                    {
                        key: 'fruit',
                        sortable: true,
                        editor: new Y.DropDownCellEditor({
                            editable: true,
                            multiple: true,
                            options: {
                                apple: 'Apple',
                                cherry: 'Cherry',
                                banana: 'Banana',
                                kiwi: 'Kiwi'
                            }
                        })
                    },
                    {
                        key: 'date',
                        sortable: true,
                        editor: new Y.DateCellEditor({
                            calendar: {
                                width:'400px',
                                showPrevMonth: true,
                                showNextMonth: true,
                                selectionMode: 'multiple'
                            }
                        })
                    }
                ],
                data: data,
                editEvent: 'dblclick',
                plugins: [
                    {
                        fn: Y.Plugin.DataTableHighlight
                    }
                ]
            }).render();
        },

        'navigate on arrow keys': function() {
            var dataTable = this._dataTable,
                activeCoords,
                boundingBox = dataTable.get('boundingBox'),
                cellCoords = {
                    topLeft: [0, 0],
                    topRight: [0, 1],
                    bottomLeft: [1, 0],
                    bottomRight: [1, 1]
                };

            dataTable.focus();
            dataTable.set('activeCoord', cellCoords.topLeft);
            dataTable.set('selection', cellCoords.topLeft);

            //simulate right arrow key press

            boundingBox.simulate('keydown', { keyCode: 39 });
            activeCoords = dataTable.get('activeCoord');

            Y.ArrayAssert.itemsAreSame(cellCoords.topRight, activeCoords, 'Right arrow should have moved selection.');

            //simulate down arrow key press

            boundingBox.simulate('keydown', { keyCode: 40 });
            activeCoords = dataTable.get('activeCoord');

            Y.ArrayAssert.itemsAreSame(cellCoords.bottomRight, activeCoords, 'Down arrow should have moved selection.');

            //simulate left arrow key press

            boundingBox.simulate('keydown', { keyCode: 37 });
            activeCoords = dataTable.get('activeCoord');

            Y.ArrayAssert.itemsAreSame(cellCoords.bottomLeft, activeCoords, 'Left arrow should have moved selection.');

            //simulate up arrow key press

            boundingBox.simulate('keydown', { keyCode: 38 });
            activeCoords = dataTable.get('activeCoord');

            Y.ArrayAssert.itemsAreSame(cellCoords.topLeft, activeCoords, 'Up arrow should have moved selection.');
        },

        'open editor on double click': function() {
            var dataTable = this._dataTable,
                firstCell = dataTable.getCell([0, 0]);

            firstCell.simulate('dblclick');

            var editorNode = Y.one('.basecelleditor');

            Y.Assert.isNotNull(editorNode, 'The editor should have been opened.');
        },

        'cancel cell editor': function() {
            var cell = this._dataTable.getCell([0, 0]),
                newVal = 'Testing editor node save.',
                originalVal = cell.html();

            cell.simulate('dblclick');

            var editorNode = Y.one('.basecelleditor'),
                cancelBtn = editorNode.all('button').item(1),
                textArea = editorNode.one('textarea');

            textArea.val(newVal);

            cancelBtn.focus().simulate('click');

            Y.Assert.areEqual(cell.html(), originalVal);
        },

        'save cell edit': function() {
            var cell = this._dataTable.getCell([0, 0]),
                newVal = 'Testing editor node save.';

            cell.simulate('dblclick');

            var editorNode = Y.one('.basecelleditor'),
                textArea = editorNode.one('textarea'),
                saveBtn = editorNode.all('button').item(0);

            textArea.val(newVal);

            saveBtn.focus().simulate('click');

            Y.Assert.areEqual(cell.html(), newVal);
        },

        'fields sorted on caret click': function() {
            var sortableHeader = Y.one('.table-sortable-column'),
                colId = sortableHeader.getData('yui3-col-id'),
                prevCellHtml,
                sortedCorrectly = true;

            sortableHeader.simulate('click');

            var sortBy = sortableHeader.get('aria-sort');

            Y.all('.table-cell.table-col-' + colId).each(
                function(item, index, collection) {
                    if (prevCellHtml) {
                        if (sortBy === 'ascending') {
                            sortedCorrectly = prevCellHtml <= item.html();
                        }
                        else {
                            sortedCorrectly = prevCellHtml >= item.html();
                        }
                    }

                    prevCellHtml = item.html();
                }
            );

            Y.Assert.isTrue(sortedCorrectly, 'Items are not sorted correctly.');
        }
    }));

    Y.Test.Runner.add(suite);

}, '', {
    requires: ['aui-datatable', 'node', 'node-event-simulate', 'test']
});
<commit_msg>AUI-1288 - jshint - parameters never used<commit_after>YUI.add('aui-datatable-tests', function(Y) {

    var suite = new Y.Test.Suite('aui-datatable');

    var data = [
        {
            active: 'no',
            address: '3271 Another Ave',
            amount: 3,
            city: 'New York',
            colors: ['red', 'blue'],
            date: '2013-01-01',
            fruit: ['apple'],
            name: 'Joan B. Jones',
            state: 'AL'
        },
        {
            active: 'maybe',
            address: '9996 Random Road',
            amount: 0,
            city: 'Los Angeles',
            colors: ['green'],
            date: '2013-01-01',
            fruit: ['cherry'],
            name: 'Bob C. Uncle',
            state: 'CA'
        },
        {
            active: 'yes',
            address: '1623 Some Street',
            amount: 5,
            city: 'San Francisco',
            colors: ['red'],
            date: '',
            fruit: ['cherry'],
            name: 'John D. Smith',
            state: 'CA'
        },
        {
            active: 'no',
            address: '3217 Another Ave',
            amount: 3,
            city: 'New York',
            colors: ['red', 'blue'],
            date: '2013-01-06',
            fruit: ['apple', 'cherry'],
            name: 'Joan E. Jones',
            state: 'KY'
        }
    ];

    new Y.DataTable({
        boundingBox: '#simple',
        columns: [
            {
                editor: new Y.TextAreaCellEditor({
                    on: {
                        cancel: function(event) {
                            console.log('cancel', event);
                        },
                        save: function(event) {
                            console.log('save', event.newVal);
                        }
                    },
                    validator: {
                        rules: {
                            value: {
                                required: true
                            }
                        }
                    }
                }),
                key: 'name',
                sortable: true
            },
            {
                editor: new Y.TextAreaCellEditor(),
                key: 'address'
            },
            {
                editor: new Y.TextAreaCellEditor(),
                key: 'city'
            },
            {
                editor: new Y.DropDownCellEditor({
                    editable: true,
                    options: ['AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FL', 'GA', 'HI', 'ID',
                        'IL', 'IN', 'IA', 'KS', 'KY', 'LA']
                }),
                key: 'state'
            },
            'amount',
            {
                editor: new Y.RadioCellEditor({
                    editable: true,
                    options: {
                        yes: 'Yes',
                        no: 'No',
                        maybe: 'Maybe'
                    }
                }),
                key: 'active'
            },
            {
                editor: new Y.CheckboxCellEditor({
                    editable: true,
                    multiple: true,
                    options: {
                        red: 'Red',
                        green: 'Green',
                        blue: 'Blue'
                    }
                }),
                key: 'colors'
            },
            {
                editor: new Y.DropDownCellEditor({
                    editable: true,
                    multiple: true,
                    options: {
                        apple: 'Apple',
                        banana: 'Banana',
                        cherry: 'Cherry',
                        kiwi: 'Kiwi'
                    }
                }),
                key: 'fruit',
                sortable: true
            },
            {
                editor: new Y.DateCellEditor({
                    calendar: {
                        selectionMode: 'multiple',
                        showNextMonth: true,
                        showPrevMonth: true,
                        width: '400px'
                    }
                }),
                key: 'date',
                sortable: true
            }
        ],
        data: data,
        editEvent: 'dblclick',
        plugins: [
            {
                fn: Y.Plugin.DataTableHighlight
            }
        ]
    }).render();

    function assertHighlightPosition(tableData) {
        var lowerXLimit,
            lowerYLimit,
            overlayActiveBorderWidth,
            overlayActiveBottomWidth,
            overlayActiveChildren,
            overlayActiveLeftHeight,
            overlayActiveNode,
            overlayActiveRightHeight,
            overlayActiveTopWidth,
            overlaySelectionNode,
            tableDataHeight,
            tableDataWidth,
            upperXLimit,
            upperYLimit;

        overlayActiveNode = Y.one('.table-highlight-overlay-active');
        overlayActiveChildren = overlayActiveNode.get('children');
        overlaySelectionNode = overlayActiveNode ? overlayActiveNode.next('.table-highlight-overlay') : null;

        lowerXLimit = tableData.getX() >= (overlayActiveNode.getX() - 1);
        lowerYLimit = tableData.getY() >= (overlayActiveNode.getY() - 1);

        overlayActiveBorderWidth = overlayActiveChildren.item(0).get('offsetHeight');
        overlayActiveBottomWidth = overlayActiveChildren.item(2).get('offsetWidth');

        overlayActiveLeftHeight = overlayActiveChildren.item(3).get('offsetHeight') + overlayActiveBorderWidth;
        overlayActiveRightHeight = overlayActiveChildren.item(1).get('offsetHeight') + overlayActiveBorderWidth;

        overlayActiveTopWidth = overlayActiveChildren.item(0).get('offsetWidth');

        tableDataHeight = tableData.get('offsetHeight');
        tableDataWidth = tableData.get('offsetWidth');

        upperXLimit = tableData.getX() <= (overlayActiveNode.getX() + 1);
        upperYLimit = tableData.getY() <= (overlayActiveNode.getY() + 1);

        Y.Assert.isTrue(
            (lowerXLimit && upperXLimit),
            'X Position of 	 and highlight are not the similar.');

        Y.Assert.isTrue(
            (lowerYLimit && upperYLimit),
            'Y Position of 	 and highlight are not the similar.');

        Y.Assert.areSame(
            tableDataWidth,
            overlayActiveBottomWidth,
            'Hightlight bottom border width ' + overlayActiveBottomWidth + ' is not same width as table data ' +
            tableDataWidth + '.');

        Y.Assert.areSame(
            tableDataWidth,
            overlayActiveTopWidth,
            'Hightlight top border width ' + overlayActiveTopWidth + ' is not same width as table data ' +
            tableDataWidth + '.');

        Y.Assert.areSame(
            tableDataHeight,
            overlayActiveLeftHeight,
            'Hightlight left border height ' + overlayActiveLeftHeight + ' is not same height as table data ' +
            tableDataHeight + '.');

        Y.Assert.areSame(
            tableDataHeight,
            overlayActiveRightHeight,
            'Hightlight right border height ' + overlayActiveRightHeight + ' is not same height as table data ' +
            tableDataHeight + '.');
    }

    suite.add(new Y.Test.Case({
        name: 'Datatable Highlight',
        'table-cell should be highlighted on click': function() {
            var test = this,
                tableData;

            tableData = Y.one('tr.table-odd td.table-col-amount');

            tableData.once('mousedown', function(event) {
                setTimeout(function() {
                    test.resume(function() {
                        assertHighlightPosition(event.currentTarget);
                    });
                }, 800);
            });

            setTimeout(function() {
                tableData.simulate('mousedown');
                tableData.simulate('mouseup');
            }, 0);

            test.wait(1000);
        },

        'table-cell should still be highlighted when table is scrolled horizontally': function() {
            var test = this,
                datatableContainer,
                datatableContent,
                tableData;

            datatableContainer = Y.one('#simple');
            datatableContent = datatableContainer.one('.table-content');
            tableData = Y.one('tr.table-odd td.table-col-amount');

            datatableContainer.setStyle('width', '300px');
            datatableContent.setStyle('overflow', 'auto');

            tableData.once('mousedown', function(event) {
                setTimeout(function() {
                    test.resume(function() {
                        assertHighlightPosition(event.currentTarget);
                    });
                }, 800);
            });

            setTimeout(function() {
                tableData.simulate('mousedown');
                tableData.simulate('mouseup');
                datatableContent.set('scrollLeft', 200);
            }, 0);

            test.wait(1000);
        }
    }));

    suite.add(new Y.Test.Case({
        name: 'Datatable',

        init: function() {
            var data = [
                {
                    active: 'no',
                    address: '3271 Another Ave',
                    amount: 3,
                    city: 'New York',
                    colors: ['red','blue'],
                    date: '2013-01-01',
                    fruit: ['apple'],
                    name: 'Joan B. Jones',
                    state: 'AL'
                },
                {
                    active: 'maybe',
                    address: '9996 Random Road',
                    amount: 0,
                    city: 'Los Angeles',
                    colors: ['green'],
                    date: '2013-01-01',
                    fruit: ['cherry'],
                    name: 'Bob C. Uncle',
                    state: 'CA'
                },
                {
                    active: 'yes',
                    address: '1623 Some Street',
                    amount: 5,
                    city: 'San Francisco',
                    colors: ['red'],
                    date: '',
                    fruit: ['cherry'],
                    name: 'John D. Smith',
                    state: 'CA'
                },
                {
                    active: 'no',
                    address: '3217 Another Ave',
                    amount: 3,
                    city: 'New York',
                    colors: ['red','blue'],
                    date: '2013-01-06',
                    fruit: ['apple','cherry'],
                    name: 'Joan E. Jones',
                    state: 'KY'
                }
            ];

            this._dataTable = new Y.DataTable({
                cssClass: 'table-striped',
                boundingBox: '#datatable',
                columns: [
                    {
                        key: 'name',
                        sortable: true,
                        editor: new Y.TextAreaCellEditor({
                            on: {
                                save: function(event) {
                                    console.log('save', event.newVal);
                                },
                                cancel: function(event) {
                                    console.log('cancel', event);
                                }
                            },
                            validator: {
                                rules: {
                                    value: {
                                        required: true
                                    }
                                }
                            }
                        })
                    },
                    {
                        key: 'address',
                        editor: new Y.TextAreaCellEditor()
                    },
                    {
                        key: 'city',
                        editor: new Y.TextAreaCellEditor()
                    },
                    {
                        key: 'state',
                        editor: new Y.DropDownCellEditor({
                            editable: true,
                            options: ['AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FL', 'GA', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA']
                        })
                    },
                    'amount',
                    {
                        key:'active',
                        editor: new Y.RadioCellEditor({
                            editable: true,
                            options: {
                                yes: 'Yes',
                                no: 'No',
                                maybe: 'Maybe'
                            }
                        })
                    },
                    {
                        key:'colors',
                        editor: new Y.CheckboxCellEditor({
                            editable: true,
                            multiple: true,
                            options: {
                                red: 'Red',
                                green: 'Green',
                                blue: 'Blue'
                            }
                        })
                    },
                    {
                        key: 'fruit',
                        sortable: true,
                        editor: new Y.DropDownCellEditor({
                            editable: true,
                            multiple: true,
                            options: {
                                apple: 'Apple',
                                cherry: 'Cherry',
                                banana: 'Banana',
                                kiwi: 'Kiwi'
                            }
                        })
                    },
                    {
                        key: 'date',
                        sortable: true,
                        editor: new Y.DateCellEditor({
                            calendar: {
                                width:'400px',
                                showPrevMonth: true,
                                showNextMonth: true,
                                selectionMode: 'multiple'
                            }
                        })
                    }
                ],
                data: data,
                editEvent: 'dblclick',
                plugins: [
                    {
                        fn: Y.Plugin.DataTableHighlight
                    }
                ]
            }).render();
        },

        'navigate on arrow keys': function() {
            var dataTable = this._dataTable,
                activeCoords,
                boundingBox = dataTable.get('boundingBox'),
                cellCoords = {
                    topLeft: [0, 0],
                    topRight: [0, 1],
                    bottomLeft: [1, 0],
                    bottomRight: [1, 1]
                };

            dataTable.focus();
            dataTable.set('activeCoord', cellCoords.topLeft);
            dataTable.set('selection', cellCoords.topLeft);

            //simulate right arrow key press

            boundingBox.simulate('keydown', { keyCode: 39 });
            activeCoords = dataTable.get('activeCoord');

            Y.ArrayAssert.itemsAreSame(cellCoords.topRight, activeCoords, 'Right arrow should have moved selection.');

            //simulate down arrow key press

            boundingBox.simulate('keydown', { keyCode: 40 });
            activeCoords = dataTable.get('activeCoord');

            Y.ArrayAssert.itemsAreSame(cellCoords.bottomRight, activeCoords, 'Down arrow should have moved selection.');

            //simulate left arrow key press

            boundingBox.simulate('keydown', { keyCode: 37 });
            activeCoords = dataTable.get('activeCoord');

            Y.ArrayAssert.itemsAreSame(cellCoords.bottomLeft, activeCoords, 'Left arrow should have moved selection.');

            //simulate up arrow key press

            boundingBox.simulate('keydown', { keyCode: 38 });
            activeCoords = dataTable.get('activeCoord');

            Y.ArrayAssert.itemsAreSame(cellCoords.topLeft, activeCoords, 'Up arrow should have moved selection.');
        },

        'open editor on double click': function() {
            var dataTable = this._dataTable,
                firstCell = dataTable.getCell([0, 0]);

            firstCell.simulate('dblclick');

            var editorNode = Y.one('.basecelleditor');

            Y.Assert.isNotNull(editorNode, 'The editor should have been opened.');
        },

        'cancel cell editor': function() {
            var cell = this._dataTable.getCell([0, 0]),
                newVal = 'Testing editor node save.',
                originalVal = cell.html();

            cell.simulate('dblclick');

            var editorNode = Y.one('.basecelleditor'),
                cancelBtn = editorNode.all('button').item(1),
                textArea = editorNode.one('textarea');

            textArea.val(newVal);

            cancelBtn.focus().simulate('click');

            Y.Assert.areEqual(cell.html(), originalVal);
        },

        'save cell edit': function() {
            var cell = this._dataTable.getCell([0, 0]),
                newVal = 'Testing editor node save.';

            cell.simulate('dblclick');

            var editorNode = Y.one('.basecelleditor'),
                textArea = editorNode.one('textarea'),
                saveBtn = editorNode.all('button').item(0);

            textArea.val(newVal);

            saveBtn.focus().simulate('click');

            Y.Assert.areEqual(cell.html(), newVal);
        },

        'fields sorted on caret click': function() {
            var sortableHeader = Y.one('.table-sortable-column'),
                colId = sortableHeader.getData('yui3-col-id'),
                prevCellHtml,
                sortedCorrectly = true;

            sortableHeader.simulate('click');

            var sortBy = sortableHeader.get('aria-sort');

            Y.all('.table-cell.table-col-' + colId).each(
                function(item) {
                    if (prevCellHtml) {
                        if (sortBy === 'ascending') {
                            sortedCorrectly = prevCellHtml <= item.html();
                        }
                        else {
                            sortedCorrectly = prevCellHtml >= item.html();
                        }
                    }

                    prevCellHtml = item.html();
                }
            );

            Y.Assert.isTrue(sortedCorrectly, 'Items are not sorted correctly.');
        }
    }));

    Y.Test.Runner.add(suite);

}, '', {
    requires: ['aui-datatable', 'node', 'node-event-simulate', 'test']
});
<|endoftext|>


<commit_before>'use strict'

const WSv2 = require('../../lib/transports/ws2')
const runExample = require('../util/run_example')

const SYMBOL = 'tXRPBTC'
const PRECISION = 'P0'
const LENGTH = '25'

module.exports = runExample({
  name: 'ws2-ob-checksum',
  ws: {
    env: true,
    connect: true,
    transform: true,
    manageOrderbooks: true // managed OBs are verified against incoming checksums
  }
}, async ({ ws, debug }) => {
  ws.onOrderBookChecksum({
    symbol: SYMBOL,
    prec: PRECISION,
    len: LENGTH
  }, cs => {
    debug('recv valid cs for %s:%s:%s %d', SYMBOL, PRECISION, LENGTH, cs)
  })

  await ws.enableFlag(WSv2.flags.CHECKSUM)
  await ws.subscribeOrderBook(SYMBOL, PRECISION, LENGTH)
})
<commit_msg>uodate 'ob_checksum' example<commit_after>'use strict'

const { args: { apiKey, apiSecret }, debug } = require('../util/setup')
const WSv2 = require('../../lib/transports/ws2')

const SYMBOL = 'tXRPBTC'
const PRECISION = 'P0'
const LENGTH = '25'

async function execute () {
  const ws = new WSv2({
    apiKey,
    apiSecret,
    transform: true,
    manageOrderbooks: true // managed OBs are verified against incoming checksums
  })
  ws.on('error', e => debug('WSv2 error: %s', e.message | e))
  await ws.open()

  ws.onOrderBookChecksum({
    symbol: SYMBOL,
    prec: PRECISION,
    len: LENGTH
  }, cs => {
    debug('recv valid cs for %s:%s:%s %d', SYMBOL, PRECISION, LENGTH, cs)
  })

  await ws.enableFlag(WSv2.flags.CHECKSUM)
  await ws.subscribeOrderBook(SYMBOL, PRECISION, LENGTH)
}

execute()
<|endoftext|>


<commit_before>const os = require('os')
const packageJson = require('../package.json')

function generateConnectionOptions (name) {
  return {
    clientProperties: {
      connection_name: name,
      powered_by: `${packageJson.name}@${packageJson.version} (${packageJson.repository.url.substr(0, packageJson.repository.url.length - 4)}/tree/${packageJson.version})`,
      repository: packageJson.repository.url,
      package: `https://www.npmjs.com/package/${packageJson.name}`,
      host: {
        name: `${os.userInfo().username}@${os.hostname()}`,
        platform: `${os.type()}@${os.release()}`,
        pid: process.pid,
        node: process.version
      }
    }
  }
}

module.exports = generateConnectionOptions
<commit_msg>🔀 Merge pull request #64 from jpwilliams/nodelay<commit_after>const os = require('os')
const packageJson = require('../package.json')

function generateConnectionOptions (name) {
  return {
    noDelay: true,
    clientProperties: {
      connection_name: name,
      powered_by: `${packageJson.name}@${packageJson.version} (${packageJson.repository.url.substr(0, packageJson.repository.url.length - 4)}/tree/${packageJson.version})`,
      repository: packageJson.repository.url,
      package: `https://www.npmjs.com/package/${packageJson.name}`,
      host: {
        name: `${os.userInfo().username}@${os.hostname()}`,
        platform: `${os.type()}@${os.release()}`,
        pid: process.pid,
        node: process.version
      }
    }
  }
}

module.exports = generateConnectionOptions
<|endoftext|>


<commit_before>let appId = process.env.KADIRA_ID;
let appSecret = process.env.KADIRA_SECRET;
if (appId && appSecret) {
	Kadira.connect(appId, appSecret);
}
<commit_msg>disabled kadira<commit_after>// let appId = process.env.KADIRA_ID;
// let appSecret = process.env.KADIRA_SECRET;
// if (appId && appSecret) {
// 	Kadira.connect(appId, appSecret);
// }
<|endoftext|>


<commit_before>if (typeof chai === "undefined" && typeof window === "undefined") {
    var chai = require("chai");
}

if (typeof expect === "undefined") {
    var expect = chai.expect;
}

if (typeof msngr === "undefined" && typeof window === "undefined") {
    var msngr = require("../../msngr");
}

describe("./objects/message.js", function () {
    "use strict";

    before(function () {
        msngr.debug = true;
    });

    beforeEach(function () {
        msngr.internal.reset();
    });

    after(function () {
        msngr.debug = false;
    });

    it("msngr - handles a message object as expected", function () {
        var m = msngr({ topic: "MyTopic", category: "MyCategory", dataType: "MyDataType" });
        expect(m).to.exist;
        expect(m.message).to.exist;
        expect(m.message.topic).to.exist;
        expect(m.message.topic).to.equal("MyTopic");
        expect(m.message.category).to.exist;
        expect(m.message.category).to.equal("MyCategory");
        expect(m.message.dataType).to.exist;
        expect(m.message.dataType).to.equal("MyDataType");
    });

    it("msngr() - converts single string into message object with a topic", function () {
        var m = msngr("MyTopic");
        expect(m).to.exist;
        expect(m.message).to.exist;
        expect(m.message.topic).to.exist;
        expect(m.message.topic).to.equal("MyTopic");
    });

    it("msngr() - converts two strings into message object with a topic and category", function () {
        var m = msngr("MyTopic", "MyCategory");
        expect(m).to.exist;
        expect(m.message).to.exist;
        expect(m.message.topic).to.exist;
        expect(m.message.topic).to.equal("MyTopic");
        expect(m.message.category).to.exist;
        expect(m.message.category).to.equal("MyCategory");
    });

    it("msngr() - converts three strings into message object with a topic, category and dataType", function () {
        var m = msngr("MyTopic", "MyCategory", "MyDataType");
        expect(m).to.exist;
        expect(m.message).to.exist;
        expect(m.message.topic).to.exist;
        expect(m.message.topic).to.equal("MyTopic");
        expect(m.message.category).to.exist;
        expect(m.message.category).to.equal("MyCategory");
        expect(m.message.dataType).to.exist;
        expect(m.message.dataType).to.equal("MyDataType");
    });

    it("msngr.internal.handlerCount - returns the correct count of registered messages", function () {
        expect(msngr.internal.handlerCount).to.exist;
        expect(msngr.internal.handlerCount).to.equal(0);
        msngr("MyTopic").on(function () { });
        expect(msngr.internal.handlerCount).to.equal(1);
        msngr("AnotherTopic").on(function () { });
        expect(msngr.internal.handlerCount).to.equal(2);
    });

    it("msngr() - multiple copies do not share message objects", function () {
        var m1 = msngr("MyTopic1");
        var m2 = msngr("MyTopic2", "MyCategory2");
        var m3 = msngr("MyTopic3", "MyCategory3", "MyDataType3");
        var m4 = msngr("MyTopic4", "MyCategory4");
        var m5 = msngr("MyTopic5");

        expect(m1).to.exist;
        expect(m2).to.exist;
        expect(m3).to.exist;
        expect(m4).to.exist;
        expect(m5).to.exist;

        expect(m1.message.topic).to.not.equal(m2.message.topic);
        expect(m2.message.topic).to.not.equal(m3.message.topic);
        expect(m3.message.topic).to.not.equal(m4.message.topic);
        expect(m4.message.topic).to.not.equal(m5.message.topic);
        expect(m5.message.topic).to.not.equal(m1.message.topic);

        expect(m2.message.category).to.not.equal(m3.message.category);
        expect(m3.message.dataType).to.not.equal(m4.message.dataType);
    });

    it("msngr().emit() / on() - Successfully emits and handles a topic only message", function (done) {
        var msg = msngr("MyTopic");
        msg.on(function (payload) {
            expect(payload).to.exist;
            expect(payload).to.equal("MyPayload");
            done();
        });

        msg.emit("MyPayload");
    });

    it("msngr().emit() / on() - Successfully emits and handles a topic and category message", function (done) {
        var msg = msngr("MyTopic", "MyCategory");
        msg.on(function (payload) {
            expect(payload).to.exist;
            expect(payload).to.equal("AnotherPayload");
            done();
        });

        msg.emit("AnotherPayload");
    });

    it("msngr().emit() / on() - Successfully emits and handles a topic, category and dataType message", function (done) {
        var msg = msngr("MyTopic", "MyCategory", "MyDataType");
        msg.on(function (payload) {
            expect(payload).to.exist;
            expect(payload).to.equal("WeePayloads!");
            done();
        });

        msg.emit("WeePayloads!");
    });

    it("msngr().emit() / on() - Setup three handlers, both receive emit payload", function (done) {
        var handled = 0;

        var msg = msngr("MyTopic", "MyCategory", "MyDataType");
        msg.on(function (payload) {
            ++handled;
            expect(payload).to.exist;
            expect(payload).to.equal("ThreeHandlers");
        });

        msg.on(function (payload) {
            ++handled;
            expect(payload).to.exist;
            expect(payload).to.equal("ThreeHandlers");
        });

        msg.on(function (payload) {
            ++handled;
            expect(payload).to.exist;
            expect(payload).to.equal("ThreeHandlers");
        });

        msg.emit("ThreeHandlers");

        setTimeout(function () {
            expect(handled).to.equal(3);
            done();
        }, 250);
    });

    it("msngr().emit() / on() - Setup two handlers, delete one and the other still receives", function (done) {
        var handled = 0;
        var answer = undefined;
        var onHandler1 = function (payload) {
            ++handled;
            answer = 1;
            expect(payload).to.exist;
            expect(payload).to.equal("TwoThenOne");
        };

        var onHandler2 = function (payload) {
            ++handled;
            answer = 5;
            expect(payload).to.exist;
            expect(payload).to.equal("TwoThenOne");
        };

        var msg = msngr("MyTopic", "MyCategory", "MyDataType");

        msg.on(onHandler1);
        msg.on(onHandler2);

        msg.drop(onHandler1);

        msg.emit("TwoThenOne");

        setTimeout(function () {
            expect(handled).to.equal(1);
            expect(answer).to.exist;
            expect(answer).to.equal(5);
            done();
        }, 250);
    });

    it("msngr().emit() / on() - Multiple handlers, callback on emit aggregates results", function (done) {
        var handled = 0;

        var msg = msngr("MyTopic", "MyCategory", "MyDataType");
        msg.on(function (payload) {
            ++handled;
            expect(payload).to.exist;
            expect(payload).to.equal("ThreeHandlers");
            return "testering";
        });

        msg.on(function (payload, async) {
            var finished = async();
            ++handled;
            expect(payload).to.exist;
            expect(payload).to.equal("ThreeHandlers");
            finished(42);
        });

        msg.on(function (payload) {
            ++handled;
            expect(payload).to.exist;
            expect(payload).to.equal("ThreeHandlers");
            return true;
        });

        msg.emit("ThreeHandlers", function (results) {
            expect(handled).to.equal(3);
            expect(results).to.exist;
            expect(results.length).to.equal(3);
            expect(results.indexOf("testering")).to.not.equal(-1);
            expect(results.indexOf(42)).to.not.equal(-1);
            expect(results.indexOf(true)).to.not.equal(-1);
            done();
        });
    });

    it("msngr().emit() / once() - once is only called one time for handling the same message", function (done) {
        var handledCount = 0;

        var msg = msngr("MyTopicTest");
        msg.once(function (payload) {
            ++handledCount;
        });

        msg.emit();
        msg.emit();
        msg.emit();
        msg.emit();

        setTimeout(function () {
            expect(handledCount).to.equal(1);
            done();
        }, 250);
    });

    it("msngr().emit(func) - if a method is passed in as first argument then that is used as callback", function (done) {
        var msg = msngr("TestTopical");
        var hitOn = false;
        msg.on(function () {
            hitOn = true;
        });
        msg.emit(function () {
            expect(hitOn).to.equal(true);
            done();
        });
    });

    it("msngr().persist().on() - persist stores and re-emits data with new on registrations", function (done) {
        var handledCount = 0;

        var msg = msngr("AnotherTopic");
        msg.persist("PayloadTwo");
        msg.on(function (payload) {
            ++handledCount;
            expect(payload).to.exist;
            expect(payload).to.equal("PayloadTwo");
            expect(handledCount).to.equal(1);
            done();
        });
        msg.cease();
    });

    it("msngr().on().persist() - registers handler then receives persisted payload", function (done) {
        var handledCount = 0;

        var msg = msngr("MyTestingTopic");
        msg.on(function (payload) {
            ++handledCount;
            expect(payload).to.exist;
            expect(payload).to.equal("MyPayload");
            expect(handledCount).to.equal(1);
            done();
        });
        msg.persist("MyPayload");
        msg.cease();

    });

    it("msngr().once().persist() - registers handler then receives persisted payload", function (done) {
        var handledCount = 0;

        var msg = msngr("MyTestingTopic");
        msg.once(function (payload) {
            ++handledCount;
            expect(payload).to.exist;
            expect(payload).to.equal("MyPayload");
            expect(handledCount).to.equal(1);
            done();
        });
        msg.persist("MyPayload");
        msg.cease();

    });

    it("msngr().persist().cease().on() - registers a payload, unregisters a payload then registers a handler", function (done) {
        var handledCount = 0;

        var msg = msngr("MyTestingTopic");
        msg.persist("MyPayload");
        msg.cease();
        msg.on(function (payload) {
            ++handledCount;
        });

        setTimeout(function () {
            expect(handledCount).to.equal(0);
            done();
        }, 250);

    });

    it("msngr().persist() - complex merging of persisted objects for ultimate ready status", function (done) {
        var msg = msngr("MyCoolTopic", "MyCat");
        var d = false;
        msg.on(function (payload) {
            // Check to make sure ready state is across the board
            expect(payload).to.exist;
            if (payload.ready1 === true && payload.ready2 === true && payload.ready3 === true && payload.ready4 === true && d === false) {
                // All statuses have come in ready!
                d = true;
                done();
            }
        });

        msg.persist({ ready1: true });
        msg.persist({ ready2: true });
        msg.persist({ ready3: true });
        msg.persist({ ready4: true });
    });

    it("msngr().persist() - passing in nothing still conducts a proper persisting of message execution in later 'on's", function (done) {
        msngr("Server", "Ready").persist();

        var calls = 0;

        msngr("Server", "Ready").on(function () {
            ++calls;
        });

        msngr("Server", "Ready").on(function () {
            ++calls;
        });

        msngr("Server", "Ready").on(function () {
            ++calls;
        });

        setTimeout(function () {
            expect(calls).to.equal(3);
            done();
        }, 250);
    });

    it("msngr().counts - when debug mode is enabled returns a counts object otherwise is undefined", function () {
        msngr.debug = true;
        var msg = msngr("test");
        expect(msg.counts).to.exist;
        expect(msg.counts.emits).to.equal(0);
        msg.emit();
        expect(msg.counts.emits).to.equal(1);

        msngr.debug = false;
        var msg2 = msngr("another");
        expect(msg2.counts).to.not.exist;
    });

});
<commit_msg>Added unit tests for invalid input<commit_after>if (typeof chai === "undefined" && typeof window === "undefined") {
    var chai = require("chai");
}

if (typeof expect === "undefined") {
    var expect = chai.expect;
}

if (typeof msngr === "undefined" && typeof window === "undefined") {
    var msngr = require("../../msngr");
}

describe("./objects/message.js", function () {
    "use strict";

    before(function () {
        msngr.debug = true;
    });

    beforeEach(function () {
        msngr.internal.reset();
    });

    after(function () {
        msngr.debug = false;
    });

    it("msngr() - throws an exception for invalid input", function () {
        expect(msngr.bind([])).to.throw();
        expect(msngr.bind()).to.throw();
        expect(msngr.bind("")).to.throw();
        expect(msngr.bind(123)).to.throw();
        expect(msngr.bind((new Date()))).to.throw();
    });

    it("msngr() - handles a message object as expected", function () {
        var m = msngr({ topic: "MyTopic", category: "MyCategory", dataType: "MyDataType" });
        expect(m).to.exist;
        expect(m.message).to.exist;
        expect(m.message.topic).to.exist;
        expect(m.message.topic).to.equal("MyTopic");
        expect(m.message.category).to.exist;
        expect(m.message.category).to.equal("MyCategory");
        expect(m.message.dataType).to.exist;
        expect(m.message.dataType).to.equal("MyDataType");
    });

    it("msngr() - converts single string into message object with a topic", function () {
        var m = msngr("MyTopic");
        expect(m).to.exist;
        expect(m.message).to.exist;
        expect(m.message.topic).to.exist;
        expect(m.message.topic).to.equal("MyTopic");
    });

    it("msngr() - converts two strings into message object with a topic and category", function () {
        var m = msngr("MyTopic", "MyCategory");
        expect(m).to.exist;
        expect(m.message).to.exist;
        expect(m.message.topic).to.exist;
        expect(m.message.topic).to.equal("MyTopic");
        expect(m.message.category).to.exist;
        expect(m.message.category).to.equal("MyCategory");
    });

    it("msngr() - converts three strings into message object with a topic, category and dataType", function () {
        var m = msngr("MyTopic", "MyCategory", "MyDataType");
        expect(m).to.exist;
        expect(m.message).to.exist;
        expect(m.message.topic).to.exist;
        expect(m.message.topic).to.equal("MyTopic");
        expect(m.message.category).to.exist;
        expect(m.message.category).to.equal("MyCategory");
        expect(m.message.dataType).to.exist;
        expect(m.message.dataType).to.equal("MyDataType");
    });

    it("msngr.internal.handlerCount - returns the correct count of registered messages", function () {
        expect(msngr.internal.handlerCount).to.exist;
        expect(msngr.internal.handlerCount).to.equal(0);
        msngr("MyTopic").on(function () { });
        expect(msngr.internal.handlerCount).to.equal(1);
        msngr("AnotherTopic").on(function () { });
        expect(msngr.internal.handlerCount).to.equal(2);
    });

    it("msngr() - multiple copies do not share message objects", function () {
        var m1 = msngr("MyTopic1");
        var m2 = msngr("MyTopic2", "MyCategory2");
        var m3 = msngr("MyTopic3", "MyCategory3", "MyDataType3");
        var m4 = msngr("MyTopic4", "MyCategory4");
        var m5 = msngr("MyTopic5");

        expect(m1).to.exist;
        expect(m2).to.exist;
        expect(m3).to.exist;
        expect(m4).to.exist;
        expect(m5).to.exist;

        expect(m1.message.topic).to.not.equal(m2.message.topic);
        expect(m2.message.topic).to.not.equal(m3.message.topic);
        expect(m3.message.topic).to.not.equal(m4.message.topic);
        expect(m4.message.topic).to.not.equal(m5.message.topic);
        expect(m5.message.topic).to.not.equal(m1.message.topic);

        expect(m2.message.category).to.not.equal(m3.message.category);
        expect(m3.message.dataType).to.not.equal(m4.message.dataType);
    });

    it("msngr().emit() / on() - Successfully emits and handles a topic only message", function (done) {
        var msg = msngr("MyTopic");
        msg.on(function (payload) {
            expect(payload).to.exist;
            expect(payload).to.equal("MyPayload");
            done();
        });

        msg.emit("MyPayload");
    });

    it("msngr().emit() / on() - Successfully emits and handles a topic and category message", function (done) {
        var msg = msngr("MyTopic", "MyCategory");
        msg.on(function (payload) {
            expect(payload).to.exist;
            expect(payload).to.equal("AnotherPayload");
            done();
        });

        msg.emit("AnotherPayload");
    });

    it("msngr().emit() / on() - Successfully emits and handles a topic, category and dataType message", function (done) {
        var msg = msngr("MyTopic", "MyCategory", "MyDataType");
        msg.on(function (payload) {
            expect(payload).to.exist;
            expect(payload).to.equal("WeePayloads!");
            done();
        });

        msg.emit("WeePayloads!");
    });

    it("msngr().emit() / on() - Setup three handlers, both receive emit payload", function (done) {
        var handled = 0;

        var msg = msngr("MyTopic", "MyCategory", "MyDataType");
        msg.on(function (payload) {
            ++handled;
            expect(payload).to.exist;
            expect(payload).to.equal("ThreeHandlers");
        });

        msg.on(function (payload) {
            ++handled;
            expect(payload).to.exist;
            expect(payload).to.equal("ThreeHandlers");
        });

        msg.on(function (payload) {
            ++handled;
            expect(payload).to.exist;
            expect(payload).to.equal("ThreeHandlers");
        });

        msg.emit("ThreeHandlers");

        setTimeout(function () {
            expect(handled).to.equal(3);
            done();
        }, 250);
    });

    it("msngr().emit() / on() - Setup two handlers, delete one and the other still receives", function (done) {
        var handled = 0;
        var answer = undefined;
        var onHandler1 = function (payload) {
            ++handled;
            answer = 1;
            expect(payload).to.exist;
            expect(payload).to.equal("TwoThenOne");
        };

        var onHandler2 = function (payload) {
            ++handled;
            answer = 5;
            expect(payload).to.exist;
            expect(payload).to.equal("TwoThenOne");
        };

        var msg = msngr("MyTopic", "MyCategory", "MyDataType");

        msg.on(onHandler1);
        msg.on(onHandler2);

        msg.drop(onHandler1);

        msg.emit("TwoThenOne");

        setTimeout(function () {
            expect(handled).to.equal(1);
            expect(answer).to.exist;
            expect(answer).to.equal(5);
            done();
        }, 250);
    });

    it("msngr().emit() / on() - Multiple handlers, callback on emit aggregates results", function (done) {
        var handled = 0;

        var msg = msngr("MyTopic", "MyCategory", "MyDataType");
        msg.on(function (payload) {
            ++handled;
            expect(payload).to.exist;
            expect(payload).to.equal("ThreeHandlers");
            return "testering";
        });

        msg.on(function (payload, async) {
            var finished = async();
            ++handled;
            expect(payload).to.exist;
            expect(payload).to.equal("ThreeHandlers");
            finished(42);
        });

        msg.on(function (payload) {
            ++handled;
            expect(payload).to.exist;
            expect(payload).to.equal("ThreeHandlers");
            return true;
        });

        msg.emit("ThreeHandlers", function (results) {
            expect(handled).to.equal(3);
            expect(results).to.exist;
            expect(results.length).to.equal(3);
            expect(results.indexOf("testering")).to.not.equal(-1);
            expect(results.indexOf(42)).to.not.equal(-1);
            expect(results.indexOf(true)).to.not.equal(-1);
            done();
        });
    });

    it("msngr().emit() / once() - once is only called one time for handling the same message", function (done) {
        var handledCount = 0;

        var msg = msngr("MyTopicTest");
        msg.once(function (payload) {
            ++handledCount;
        });

        msg.emit();
        msg.emit();
        msg.emit();
        msg.emit();

        setTimeout(function () {
            expect(handledCount).to.equal(1);
            done();
        }, 250);
    });

    it("msngr().emit(func) - if a method is passed in as first argument then that is used as callback", function (done) {
        var msg = msngr("TestTopical");
        var hitOn = false;
        msg.on(function () {
            hitOn = true;
        });
        msg.emit(function () {
            expect(hitOn).to.equal(true);
            done();
        });
    });

    it("msngr().persist().on() - persist stores and re-emits data with new on registrations", function (done) {
        var handledCount = 0;

        var msg = msngr("AnotherTopic");
        msg.persist("PayloadTwo");
        msg.on(function (payload) {
            ++handledCount;
            expect(payload).to.exist;
            expect(payload).to.equal("PayloadTwo");
            expect(handledCount).to.equal(1);
            done();
        });
        msg.cease();
    });

    it("msngr().on().persist() - registers handler then receives persisted payload", function (done) {
        var handledCount = 0;

        var msg = msngr("MyTestingTopic");
        msg.on(function (payload) {
            ++handledCount;
            expect(payload).to.exist;
            expect(payload).to.equal("MyPayload");
            expect(handledCount).to.equal(1);
            done();
        });
        msg.persist("MyPayload");
        msg.cease();

    });

    it("msngr().once().persist() - registers handler then receives persisted payload", function (done) {
        var handledCount = 0;

        var msg = msngr("MyTestingTopic");
        msg.once(function (payload) {
            ++handledCount;
            expect(payload).to.exist;
            expect(payload).to.equal("MyPayload");
            expect(handledCount).to.equal(1);
            done();
        });
        msg.persist("MyPayload");
        msg.cease();

    });

    it("msngr().persist().cease().on() - registers a payload, unregisters a payload then registers a handler", function (done) {
        var handledCount = 0;

        var msg = msngr("MyTestingTopic");
        msg.persist("MyPayload");
        msg.cease();
        msg.on(function (payload) {
            ++handledCount;
        });

        setTimeout(function () {
            expect(handledCount).to.equal(0);
            done();
        }, 250);

    });

    it("msngr().persist() - complex merging of persisted objects for ultimate ready status", function (done) {
        var msg = msngr("MyCoolTopic", "MyCat");
        var d = false;
        msg.on(function (payload) {
            // Check to make sure ready state is across the board
            expect(payload).to.exist;
            if (payload.ready1 === true && payload.ready2 === true && payload.ready3 === true && payload.ready4 === true && d === false) {
                // All statuses have come in ready!
                d = true;
                done();
            }
        });

        msg.persist({ ready1: true });
        msg.persist({ ready2: true });
        msg.persist({ ready3: true });
        msg.persist({ ready4: true });
    });

    it("msngr().persist() - passing in nothing still conducts a proper persisting of message execution in later 'on's", function (done) {
        msngr("Server", "Ready").persist();

        var calls = 0;

        msngr("Server", "Ready").on(function () {
            ++calls;
        });

        msngr("Server", "Ready").on(function () {
            ++calls;
        });

        msngr("Server", "Ready").on(function () {
            ++calls;
        });

        setTimeout(function () {
            expect(calls).to.equal(3);
            done();
        }, 250);
    });

    it("msngr().counts - when debug mode is enabled returns a counts object otherwise is undefined", function () {
        msngr.debug = true;
        var msg = msngr("test");
        expect(msg.counts).to.exist;
        expect(msg.counts.emits).to.equal(0);
        msg.emit();
        expect(msg.counts.emits).to.equal(1);

        msngr.debug = false;
        var msg2 = msngr("another");
        expect(msg2.counts).to.not.exist;
    });

});
<|endoftext|>