<commit_before>;

(function($) {
  $.fn.highchartTable = function() {

    var allowedGraphTypes = ['column', 'line', 'area', 'spline', 'pie'];

    var getCallable = function (table, attribute) {
      var callback = $(table).data(attribute);
      if (typeof callback != 'undefined') {
        var infosCallback = callback.split('.');
        var callable      = window[infosCallback[0]];
        for(var i = 1, infosCallbackLength = infosCallback.length; i < infosCallbackLength; i++) {
          callable = callable[infosCallback[i]];
        }
        return callable;
      }
    };

    this.each(function() {
      var table = $(this);
      var $table = $(table);
      var nbYaxis = 1;

      // Retrieve graph title from the table caption
      var captions   = $('caption', table);
      var graphTitle = captions.length ? $(captions[0]).text() : '';

      var graphContainer;
      if ($table.data('graph-container-before') != 1) {
        // Retrieve where the graph must be displayed from the graph-container attribute
        var graphContainerSelector = $table.data('graph-container');
        if (!graphContainerSelector) {
          throw "graph-container data attribute is mandatory";
        }

        if (graphContainerSelector[0] === '#' || graphContainerSelector.indexOf('..')===-1) {
          // Absolute selector path
          graphContainer = $(graphContainerSelector);
        } else {
          var referenceNode                 = table;
          var currentGraphContainerSelector = graphContainerSelector;

          while (currentGraphContainerSelector.indexOf('..')!==-1) {
            currentGraphContainerSelector = currentGraphContainerSelector.replace(/^.. /, '');
            referenceNode = referenceNode.parent();
          }

          graphContainer = $(currentGraphContainerSelector, referenceNode);
        }
        if (graphContainer.length !== 1) {
          throw "graph-container is not available in this DOM or available multiple times";
        }
        graphContainer = graphContainer[0];
      } else {
        $table.before('

');
        graphContainer = $table.prev();
        graphContainer = graphContainer[0];
      }

      // Retrieve graph type from graph-type attribute
      var globalGraphType = $table.data('graph-type');
      if (!globalGraphType) {
        throw "graph-type data attribute is mandatory";
      }
      if ($.inArray(globalGraphType, allowedGraphTypes) == -1) {
        throw "graph-container data attribute must be one of " + allowedGraphTypes.join(', ');
      }

      var stackingType = $table.data('graph-stacking');
      if (!stackingType) {
        stackingType = 'normal';
      }

      var isGraphInverted = $table.data('graph-inverted') == 1;

      // Retrieve series titles
      var ths            = $('thead th', table);
      var columns        = [];
      var vlines         = [];
      var graphIsStacked = false;
      ths.each(function(indexTh, th) {
        var columnScale = $(th).data('graph-value-scale');

        var serieGraphType = $(th).data('graph-type');
        if($.inArray(serieGraphType, allowedGraphTypes) == -1) {
          serieGraphType = globalGraphType;
        }

        var serieStackGroup = $(th).data('graph-stack-group');
        if(serieStackGroup) {
          graphIsStacked = true;
        }

        if (typeof $(th).data('graph-yaxis') != 'undefined' && $(th).data('graph-yaxis')  == '1') {
          nbYaxis = 2;
        }

        if (typeof $(th).data('graph-vline-x') == 'undefined') {
            columns[indexTh] = {
              libelle:   $(th).text(),
              scale:     typeof columnScale != 'undefined' ? parseFloat(columnScale) : 1,
              graphType: serieGraphType,
              stack:     serieStackGroup,
              color:     $(th).data('graph-color'),
              visible:   !$(th).data('graph-hidden'),
              unit:      $(th).data('graph-unit'),
              yAxis:     typeof $(th).data('graph-yaxis') != 'undefined' ? $(th).data('graph-yaxis') : 0,
              dashStyle: $(th).data('graph-dash-style') || 'solid'
            };
        } else {
            vlines[indexTh] = {
              libelle:   $(th).text(),
              x:         $(th).data('graph-vline-x'),
              height:    $(th).data('graph-vline-height'),
              color:     $(th).data('graph-color'),
              visible:   !$(th).data('graph-hidden'),
              name:      $(th).data('graph-vline-name'),
              yAxis:     typeof $(th).data('graph-yaxis') != 'undefined' ? $(th).data('graph-yaxis') : 0,
              dashStyle: $(th).data('graph-dash-style') || 'solid'
            };
        }
      });

      var series = [];
      $(columns).each(function(indexColumn, column) {
        if(indexColumn!=0) {
          series.push({
            name:      column.libelle + (column.unit ? ' (' + column.unit + ')' : ''),
            data:      [],
            type:      column.graphType,
            stack:     column.stack,
            color:     column.color,
            visible:   column.visible,
            yAxis:     column.yAxis,
            dashStyle: column.dashStyle,
            marker: {
                enabled: false
            },
            dataLabels: {
              x:       isGraphInverted ? 15 : 0,
              enabled: $table.data('graph-datalabels-enabled') == 1,
              align:   typeof $table.data('graph-datalabels-align') != 'undefined' ? $table.data('graph-datalabels-align') : 'center'
            }
          });
        }
      });

      $(vlines).each(function(indexColumn, vline) {
        if (typeof vline != 'undefined') {
          series.push({
            name:    vline.libelle,
            data:    [{x: vline.x, y:0, name: vline.name}, {x:vline.x, y:vline.height, name: vline.name}],
            type:    'spline',
            color:   vline.color,
            visible: vline.visible,
            marker: {
              enabled: false
            }
          });
        }
      });

      var xValues = [];
      var rows = $('tbody:first tr', table);
      rows.each(function(indexRow, row) {
        if (!!$(row).data('graph-skip')) {
          return;
        }

        var tds = $('td', row);
        tds.each(function(indexTd, td) {
          var cellValue;
          if (indexTd==0) {
            cellValue = $(td).text();
            xValues.push(cellValue);
          } else {
            var rawCellValue = $(td).text();
            if (rawCellValue.length==0) {
              series[indexTd-1].data.push(null);
            } else {
              var cleanedCellValue = rawCellValue.replace(/ /g, '').replace(/,/, '.');
              cellValue = Math.round(parseFloat(cleanedCellValue) * columns[indexTd].scale * 100) / 100;

                var dataGraphX = $(td).data('graph-x');

                if ($table.data('graph-xaxis-type') == 'datetime') {
                  dataGraphX    = $('td', $(row)).first().text();
                  var dateInfos = dataGraphX.split('-');
                  var date      = parseDate(dateInfos);
                  dataGraphX    = date.getTime() - date.getTimezoneOffset()*60*1000;
                }

                var serieDataItem = {
                  name:   typeof $(td).data('graph-name') != 'undefined' ? $(td).data('graph-name') : rawCellValue,
                  y:      cellValue,
                  x:      dataGraphX //undefined if no x defined in table
                };

                var callablePoint = getCallable(table, 'graph-point-callback');
                if (callablePoint) {
                  serieDataItem.events = {
                    click: function () {
                        return callablePoint(this);
                      }
                  };
                }

                if (columns[indexTd].graphType === 'pie') {
                  if ($(td).data('graph-item-highlight')) {
                    serieDataItem.sliced = 1;
                  }
                }

                if (typeof $(td).data('graph-item-color') != 'undefined') {
                  serieDataItem.color = $(td).data('graph-item-color');
                }

                series[indexTd-1].data.push(serieDataItem);
            }
          }
        });

      });

      var yAxisConfig = [];
      var yAxisNum;
      for (yAxisNum=1 ; yAxisNum <= nbYaxis ; yAxisNum++) {
        var yAxisConfigCurrentAxis = {
          title: {
            text: typeof $table.data('graph-yaxis-'+yAxisNum+'-title-text') != 'undefined'  ? $table.data('graph-yaxis-'+yAxisNum+'-title-text') : "Valeur"
          },
          max:          typeof $table.data('graph-yaxis-'+yAxisNum+'-max') != 'undefined' ? $table.data('graph-yaxis-'+yAxisNum+'-max') : null,
          min:          typeof $table.data('graph-yaxis-'+yAxisNum+'-min') != 'undefined' ? $table.data('graph-yaxis-'+yAxisNum+'-min') : null,
          reversed:     $table.data('graph-yaxis-'+yAxisNum+'-reversed') == '1',
          opposite:     $table.data('graph-yaxis-'+yAxisNum+'-opposite') == '1',
          tickInterval: $table.data('graph-yaxis-'+yAxisNum+'-tick-interval') || null,
          labels: {
            rotation: $table.data('graph-yaxis-'+yAxisNum+'-rotation') || 0
          },
          startOnTick: $table.data('graph-yaxis-'+yAxisNum+'-start-on-tick') !== "0",
          endOnTick:   $table.data('graph-yaxis-'+yAxisNum+'-end-on-tick') !== "0"
        };

        var callableYAxisFormatter = getCallable(table, 'graph-yaxis-'+yAxisNum+'-formatter-callback');
        if (callableYAxisFormatter) {
          yAxisConfigCurrentAxis.labels.formatter = function () {
              return callableYAxisFormatter(this.value);
          };
        }

        yAxisConfig.push(yAxisConfigCurrentAxis);
      }

      var defaultColors = [
        '#4572A7',
        '#AA4643',
        '#89A54E',
        '#80699B',
        '#3D96AE',
        '#DB843D',
        '#92A8CD',
        '#A47D7C',
        '#B5CA92'
      ];
      var colors = [];

      var themeColors = typeof Highcharts.theme != 'undefined' && typeof Highcharts.theme.colors != 'undefined' ? Highcharts.theme.colors : [];

      for(var i=0; i<9; i++) {
        var dataname = 'graph-color-' + (i+1);
        colors.push(typeof $table.data(dataname) != 'undefined' ? $table.data(dataname) : typeof themeColors[i] != 'undefined' ? themeColors[i] : defaultColors[i]);
      }

      var highChartConfig = {
        colors: colors,
        chart: {
          renderTo:     graphContainer,
          inverted:     isGraphInverted,
          marginTop:    $table.data('graph-margin-top'),
          marginRight:  $table.data('graph-margin-right') || 50,
          marginBottom: $table.data('graph-margin-bottom') || 70,
          marginLeft:   $table.data('graph-margin-left') || 80,
          spacingTop:   $table.data('graph-spacing-top') || 10,
          height:       $table.data('graph-height') || null
        },
        title: {
          text: graphTitle
        },
        subtitle: {
          text: $table.data('graph-subtitle-text') || ''
        },
        legend: {
          enabled:     $table.data('graph-legend-disabled') != '1',
          layout:      typeof $table.data('graph-legend-layout') != 'undefined' ? $table.data('graph-legend-layout') :  'horizontal',
          symbolWidth: $table.data('graph-legend-width') || 30,
          x:           $table.data('graph-legend-x') || 15,
          y:           $table.data('graph-legend-y') || 0
        },
        xAxis: {
          categories:             ($table.data('graph-xaxis-type') != 'datetime') ? xValues : undefined,
          type:                   ($table.data('graph-xaxis-type') == 'datetime') ? 'datetime' :  undefined,
          reversed:               $table.data('graph-xaxis-reversed') == '1',
          opposite:               $table.data('graph-xaxis-opposite') == '1',
          showLastLabel:          true,
          tickInterval:           $table.data('graph-xaxis-tick-interval') || null,
          dateTimeLabelFormats:   { //by default, we display the day and month on the datetime graphs
            second: '%e. %b',
            minute: '%e. %b',
            hour:   '%e. %b',
            day:    '%e. %b',
            week:   '%e. %b',
            month:  '%e. %b',
            year:   '%e. %b'
          },
          labels:
          {
            rotation: $table.data('graph-xaxis-rotation') || 0,
            align:    $table.data('graph-xaxis-align') || 'center'
          },
          startOnTick: $table.data('graph-xaxis-start-on-tick'),
          endOnTick:   $table.data('graph-xaxis-end-on-tick'),
          min: getXAxisMinMax(table, 'min'),
          max: getXAxisMinMax(table, 'max'),
          alternateGridColor: $table.data('graph-xaxis-alternateGridColor') || null,
          title: {
            text: $table.data('graph-xaxis-title-text') || null
          },
          gridLineWidth:     typeof $table.data('graph-xaxis-gridLine-width') != 'undefined' ? $table.data('graph-xaxis-gridLine-width') : 0,
          gridLineDashStyle: $table.data('graph-xaxis-gridLine-style') || 'ShortDot'
        },
        yAxis: yAxisConfig,
        tooltip: {
            formatter: function() {
              if ($table.data('graph-xaxis-type') == 'datetime') {
                return ''+ this.series.name +'
'+  Highcharts.dateFormat('%e. %b', this.x) +' : '+ this.y;
              } else {
                return '' + this.series.name + ' : ' + this.point.name;
              }
            }
        },
        credits: {
          enabled: false
        },
        plotOptions: {
          line: {
            dataLabels: {
              enabled: true
            },
            lineWidth: $table.data('graph-line-width') || 2
          },
          area: {
            lineWidth:   $table.data('graph-line-width') || 2,
            shadow:      typeof $table.data('graph-line-shadow') != 'undefined' ? $table.data('graph-line-shadow') : true,
            fillOpacity: typeof $table.data('graph-area-fillOpacity') != 'undefined' ? $table.data('graph-area-fillOpacity') : 0.75
          },
          pie: {
            allowPointSelect: true,
            dataLabels: {
              enabled: true
            },
            showInLegend: 0,
            size:         '80%'
          },
          series: {
            animation:       false,
            stickyTracking : false,
            stacking:        graphIsStacked ? stackingType : null,
            groupPadding:    typeof $table.data('graph-group-padding') != 'undefined' ? $table.data('graph-group-padding') : 0
          }
        },
        series: series,
        exporting: {
            filename: graphTitle.replace(/ /g, '_'),
            buttons: {
              exportButton: {
                menuItems: null,
                onclick: function() {
                  this.exportChart();
                }
              }
            }
          }
      };

      new Highcharts.Chart(highChartConfig);

      //for fluent api
      return this;
    });
  };

  var getXAxisMinMax = function(table, minOrMax) {
    var value = $(table).data('graph-xaxis-'+minOrMax);
    if (typeof value != 'undefined') {
      if ($(table).data('graph-xaxis-type') == 'datetime') {
        var dateInfos = value.split('-');
        var date      = parseDate(dateInfos);
        return date.getTime() - date.getTimezoneOffset()*60*1000;
      }
      return value;
    }
    return null;
  };

  var parseDate = function(dateInfos) {
    return new Date(parseInt(dateInfos[0], 10), parseInt(dateInfos[1], 10)-1, parseInt(dateInfos[2], 10));
  };

})(jQuery);
<commit_msg>Added data-graph-skip attribute<commit_after>;

(function($) {
  $.fn.highchartTable = function() {

    var allowedGraphTypes = ['column', 'line', 'area', 'spline', 'pie'];

    var getCallable = function (table, attribute) {
      var callback = $(table).data(attribute);
      if (typeof callback != 'undefined') {
        var infosCallback = callback.split('.');
        var callable      = window[infosCallback[0]];
        for(var i = 1, infosCallbackLength = infosCallback.length; i < infosCallbackLength; i++) {
          callable = callable[infosCallback[i]];
        }
        return callable;
      }
    };

    this.each(function() {
      var table = $(this);
      var $table = $(table);
      var nbYaxis = 1;

      // Retrieve graph title from the table caption
      var captions   = $('caption', table);
      var graphTitle = captions.length ? $(captions[0]).text() : '';

      var graphContainer;
      if ($table.data('graph-container-before') != 1) {
        // Retrieve where the graph must be displayed from the graph-container attribute
        var graphContainerSelector = $table.data('graph-container');
        if (!graphContainerSelector) {
          throw "graph-container data attribute is mandatory";
        }

        if (graphContainerSelector[0] === '#' || graphContainerSelector.indexOf('..')===-1) {
          // Absolute selector path
          graphContainer = $(graphContainerSelector);
        } else {
          var referenceNode                 = table;
          var currentGraphContainerSelector = graphContainerSelector;

          while (currentGraphContainerSelector.indexOf('..')!==-1) {
            currentGraphContainerSelector = currentGraphContainerSelector.replace(/^.. /, '');
            referenceNode = referenceNode.parent();
          }

          graphContainer = $(currentGraphContainerSelector, referenceNode);
        }
        if (graphContainer.length !== 1) {
          throw "graph-container is not available in this DOM or available multiple times";
        }
        graphContainer = graphContainer[0];
      } else {
        $table.before('

');
        graphContainer = $table.prev();
        graphContainer = graphContainer[0];
      }

      // Retrieve graph type from graph-type attribute
      var globalGraphType = $table.data('graph-type');
      if (!globalGraphType) {
        throw "graph-type data attribute is mandatory";
      }
      if ($.inArray(globalGraphType, allowedGraphTypes) == -1) {
        throw "graph-container data attribute must be one of " + allowedGraphTypes.join(', ');
      }

      var stackingType = $table.data('graph-stacking');
      if (!stackingType) {
        stackingType = 'normal';
      }

      var isGraphInverted = $table.data('graph-inverted') == 1;

      // Retrieve series titles
      var ths            = $('thead th', table);
      var columns        = [];
      var vlines         = [];
      var skippedColumns = 0;
      var graphIsStacked = false;
      ths.each(function(indexTh, th) {
        var columnScale = $(th).data('graph-value-scale');

        var serieGraphType = $(th).data('graph-type');
        if($.inArray(serieGraphType, allowedGraphTypes) == -1) {
          serieGraphType = globalGraphType;
        }

        var serieStackGroup = $(th).data('graph-stack-group');
        if(serieStackGroup) {
          graphIsStacked = true;
        }

        if (typeof $(th).data('graph-yaxis') != 'undefined' && $(th).data('graph-yaxis')  == '1') {
          nbYaxis = 2;
        }

        var isColumnSkipped = $(th).data('graph-skip') == 1;
        if (isColumnSkipped)
        {
          skippedColumns = skippedColumns + 1
        }

        var object = {
          libelle:   $(th).text(),
          skip:      isColumnSkipped,
          indexTd:   indexTh - skippedColumns - 1,
          color:     $(th).data('graph-color'),
          visible:   !$(th).data('graph-hidden'),
          yAxis:     typeof $(th).data('graph-yaxis') != 'undefined' ? $(th).data('graph-yaxis') : 0,
          dashStyle: $(th).data('graph-dash-style') || 'solid'
        };

        if (typeof $(th).data('graph-vline-x') == 'undefined') {
          object.scale     = typeof columnScale != 'undefined' ? parseFloat(columnScale) : 1;
          object.graphType = serieGraphType;
          object.stack     = serieStackGroup;
          object.unit      = $(th).data('graph-unit');
          columns[indexTh] = object;
        } else {
          object.x      = $(th).data('graph-vline-x');
          object.height = $(th).data('graph-vline-height');
          object.name   = $(th).data('graph-vline-name');
          vlines[indexTh] = object;
        }
      });

      var series = [];
      $(columns).each(function(indexColumn, column) {
        if(indexColumn!=0 && !column.skip) {
          series.push({
            name:      column.libelle + (column.unit ? ' (' + column.unit + ')' : ''),
            data:      [],
            type:      column.graphType,
            stack:     column.stack,
            color:     column.color,
            visible:   column.visible,
            yAxis:     column.yAxis,
            dashStyle: column.dashStyle,
            marker: {
                enabled: false
            },
            dataLabels: {
              x:       isGraphInverted ? 15 : 0,
              enabled: $table.data('graph-datalabels-enabled') == 1,
              align:   typeof $table.data('graph-datalabels-align') != 'undefined' ? $table.data('graph-datalabels-align') : 'center'
            }
          });
        }
      });

      $(vlines).each(function(indexColumn, vline) {
        if (typeof vline != 'undefined' && !vline.skip) {
          series.push({
            name:    vline.libelle,
            data:    [{x: vline.x, y:0, name: vline.name}, {x:vline.x, y:vline.height, name: vline.name}],
            type:    'spline',
            color:   vline.color,
            visible: vline.visible,
            marker: {
              enabled: false
            }
          });
        }
      });

      var xValues = [];
      var rows = $('tbody:first tr', table);
      rows.each(function(indexRow, row) {
        if (!!$(row).data('graph-skip')) {
          return;
        }

        var tds = $('td', row);
        tds.each(function(indexTd, td) {
          var cellValue;
          var column = columns[indexTd];

          if (column.skip) {
            return;
          }
          if (indexTd==0) {
            cellValue = $(td).text();
            xValues.push(cellValue);
          } else {
            var rawCellValue = $(td).text();
            var serie  = series[column.indexTd];

            if (rawCellValue.length==0) {
              serie.data.push(null);
            } else {
              var cleanedCellValue = rawCellValue.replace(/ /g, '').replace(/,/, '.');
              cellValue = Math.round(parseFloat(cleanedCellValue) * column.scale * 100) / 100;

                var dataGraphX = $(td).data('graph-x');

                if ($table.data('graph-xaxis-type') == 'datetime') {
                  dataGraphX    = $('td', $(row)).first().text();
                  var dateInfos = dataGraphX.split('-');
                  var date      = parseDate(dateInfos);
                  dataGraphX    = date.getTime() - date.getTimezoneOffset()*60*1000;
                }

                var serieDataItem = {
                  name:   typeof $(td).data('graph-name') != 'undefined' ? $(td).data('graph-name') : rawCellValue,
                  y:      cellValue,
                  x:      dataGraphX //undefined if no x defined in table
                };

                var callablePoint = getCallable(table, 'graph-point-callback');
                if (callablePoint) {
                  serieDataItem.events = {
                    click: function () {
                        return callablePoint(this);
                      }
                  };
                }

                if (column.graphType === 'pie') {
                  if ($(td).data('graph-item-highlight')) {
                    serieDataItem.sliced = 1;
                  }
                }

                if (typeof $(td).data('graph-item-color') != 'undefined') {
                  serieDataItem.color = $(td).data('graph-item-color');
                }

              serie.data.push(serieDataItem);
            }
          }
        });

      });

      var yAxisConfig = [];
      var yAxisNum;
      for (yAxisNum=1 ; yAxisNum <= nbYaxis ; yAxisNum++) {
        var yAxisConfigCurrentAxis = {
          title: {
            text: typeof $table.data('graph-yaxis-'+yAxisNum+'-title-text') != 'undefined'  ? $table.data('graph-yaxis-'+yAxisNum+'-title-text') : "Valeur"
          },
          max:          typeof $table.data('graph-yaxis-'+yAxisNum+'-max') != 'undefined' ? $table.data('graph-yaxis-'+yAxisNum+'-max') : null,
          min:          typeof $table.data('graph-yaxis-'+yAxisNum+'-min') != 'undefined' ? $table.data('graph-yaxis-'+yAxisNum+'-min') : null,
          reversed:     $table.data('graph-yaxis-'+yAxisNum+'-reversed') == '1',
          opposite:     $table.data('graph-yaxis-'+yAxisNum+'-opposite') == '1',
          tickInterval: $table.data('graph-yaxis-'+yAxisNum+'-tick-interval') || null,
          labels: {
            rotation: $table.data('graph-yaxis-'+yAxisNum+'-rotation') || 0
          },
          startOnTick: $table.data('graph-yaxis-'+yAxisNum+'-start-on-tick') !== "0",
          endOnTick:   $table.data('graph-yaxis-'+yAxisNum+'-end-on-tick') !== "0"
        };

        var callableYAxisFormatter = getCallable(table, 'graph-yaxis-'+yAxisNum+'-formatter-callback');
        if (callableYAxisFormatter) {
          yAxisConfigCurrentAxis.labels.formatter = function () {
              return callableYAxisFormatter(this.value);
          };
        }

        yAxisConfig.push(yAxisConfigCurrentAxis);
      }

      var defaultColors = [
        '#4572A7',
        '#AA4643',
        '#89A54E',
        '#80699B',
        '#3D96AE',
        '#DB843D',
        '#92A8CD',
        '#A47D7C',
        '#B5CA92'
      ];
      var colors = [];

      var themeColors = typeof Highcharts.theme != 'undefined' && typeof Highcharts.theme.colors != 'undefined' ? Highcharts.theme.colors : [];

      for(var i=0; i<9; i++) {
        var dataname = 'graph-color-' + (i+1);
        colors.push(typeof $table.data(dataname) != 'undefined' ? $table.data(dataname) : typeof themeColors[i] != 'undefined' ? themeColors[i] : defaultColors[i]);
      }

      var highChartConfig = {
        colors: colors,
        chart: {
          renderTo:     graphContainer,
          inverted:     isGraphInverted,
          marginTop:    $table.data('graph-margin-top'),
          marginRight:  $table.data('graph-margin-right') || 50,
          marginBottom: $table.data('graph-margin-bottom') || 70,
          marginLeft:   $table.data('graph-margin-left') || 80,
          spacingTop:   $table.data('graph-spacing-top') || 10,
          height:       $table.data('graph-height') || null
        },
        title: {
          text: graphTitle
        },
        subtitle: {
          text: $table.data('graph-subtitle-text') || ''
        },
        legend: {
          enabled:     $table.data('graph-legend-disabled') != '1',
          layout:      typeof $table.data('graph-legend-layout') != 'undefined' ? $table.data('graph-legend-layout') :  'horizontal',
          symbolWidth: $table.data('graph-legend-width') || 30,
          x:           $table.data('graph-legend-x') || 15,
          y:           $table.data('graph-legend-y') || 0
        },
        xAxis: {
          categories:             ($table.data('graph-xaxis-type') != 'datetime') ? xValues : undefined,
          type:                   ($table.data('graph-xaxis-type') == 'datetime') ? 'datetime' :  undefined,
          reversed:               $table.data('graph-xaxis-reversed') == '1',
          opposite:               $table.data('graph-xaxis-opposite') == '1',
          showLastLabel:          true,
          tickInterval:           $table.data('graph-xaxis-tick-interval') || null,
          dateTimeLabelFormats:   { //by default, we display the day and month on the datetime graphs
            second: '%e. %b',
            minute: '%e. %b',
            hour:   '%e. %b',
            day:    '%e. %b',
            week:   '%e. %b',
            month:  '%e. %b',
            year:   '%e. %b'
          },
          labels:
          {
            rotation: $table.data('graph-xaxis-rotation') || 0,
            align:    $table.data('graph-xaxis-align') || 'center'
          },
          startOnTick: $table.data('graph-xaxis-start-on-tick'),
          endOnTick:   $table.data('graph-xaxis-end-on-tick'),
          min: getXAxisMinMax(table, 'min'),
          max: getXAxisMinMax(table, 'max'),
          alternateGridColor: $table.data('graph-xaxis-alternateGridColor') || null,
          title: {
            text: $table.data('graph-xaxis-title-text') || null
          },
          gridLineWidth:     typeof $table.data('graph-xaxis-gridLine-width') != 'undefined' ? $table.data('graph-xaxis-gridLine-width') : 0,
          gridLineDashStyle: $table.data('graph-xaxis-gridLine-style') || 'ShortDot'
        },
        yAxis: yAxisConfig,
        tooltip: {
            formatter: function() {
              if ($table.data('graph-xaxis-type') == 'datetime') {
                return ''+ this.series.name +'
'+  Highcharts.dateFormat('%e. %b', this.x) +' : '+ this.y;
              } else {
                return '' + this.series.name + ' : ' + this.point.name;
              }
            }
        },
        credits: {
          enabled: false
        },
        plotOptions: {
          line: {
            dataLabels: {
              enabled: true
            },
            lineWidth: $table.data('graph-line-width') || 2
          },
          area: {
            lineWidth:   $table.data('graph-line-width') || 2,
            shadow:      typeof $table.data('graph-line-shadow') != 'undefined' ? $table.data('graph-line-shadow') : true,
            fillOpacity: typeof $table.data('graph-area-fillOpacity') != 'undefined' ? $table.data('graph-area-fillOpacity') : 0.75
          },
          pie: {
            allowPointSelect: true,
            dataLabels: {
              enabled: true
            },
            showInLegend: 0,
            size:         '80%'
          },
          series: {
            animation:       false,
            stickyTracking : false,
            stacking:        graphIsStacked ? stackingType : null,
            groupPadding:    typeof $table.data('graph-group-padding') != 'undefined' ? $table.data('graph-group-padding') : 0
          }
        },
        series: series,
        exporting: {
            filename: graphTitle.replace(/ /g, '_'),
            buttons: {
              exportButton: {
                menuItems: null,
                onclick: function() {
                  this.exportChart();
                }
              }
            }
          }
      };

      new Highcharts.Chart(highChartConfig);

      //for fluent api
      return this;
    });
  };

  var getXAxisMinMax = function(table, minOrMax) {
    var value = $(table).data('graph-xaxis-'+minOrMax);
    if (typeof value != 'undefined') {
      if ($(table).data('graph-xaxis-type') == 'datetime') {
        var dateInfos = value.split('-');
        var date      = parseDate(dateInfos);
        return date.getTime() - date.getTimezoneOffset()*60*1000;
      }
      return value;
    }
    return null;
  };

  var parseDate = function(dateInfos) {
    return new Date(parseInt(dateInfos[0], 10), parseInt(dateInfos[1], 10)-1, parseInt(dateInfos[2], 10));
  };

})(jQuery);
<|endoftext|>


<commit_before>module.exports = {
  patterns: {
    'img/pages/**/hero-*.png': {
      format: 'jpg',
      formatParams: {
        quality: 70
      }
    }
  },
  reload: function() {
    delete require.cache[__filename];
    this.patterns = require(__filename).patterns;
  }
};
<commit_msg>document image-convert.config.js.<commit_after>// This file contains a `patterns` export that describes how
// various images in the project need to be converted for
// deployment.
//
// Each key of `patterns` is a glob pattern that matches at
// least one image in the project. The value is an object with
// the following structure:
//
// * `format` is one of `'png'`, `'jpg'`, or `'gif'`, and specifies
//   the format to convert the matched images to. If undefined,
//   the images will retain their original format.
// * `formatParams` specifies parameters to pass to the
//   image encoder. For more details, see
//   https://github.com/EyalAr/lwip#get-as-a-buffer.
//
// Note that this file also exports a `reload` function, which
// can be used to dynamically reload the module's exported data.
// This was chosen as an alternative to JSON because we wanted
// the freedom to use constants and other JavaScript features to
// avoid repetition in our data.

module.exports = {
  patterns: {
    'img/pages/**/hero-*.png': {
      format: 'jpg',
      formatParams: {
        quality: 70
      }
    }
  },
  reload: function() {
    delete require.cache[__filename];
    this.patterns = require(__filename).patterns;
  }
};
<|endoftext|>


<commit_before>/************************************************************************
*************************************************************************
@Name :       	jRating - jQuery Plugin
@Revison :    	2.2
@Date : 		26/01/2011
@Author:     	 ALPIXEL - (www.myjqueryplugins.com - www.alpixel.fr)
@License :		 Open Source - MIT License : http://www.opensource.org/licenses/mit-license.php

**************************************************************************
*************************************************************************/
(function($) {
	$.fn.jRating = function(op) {
		var defaults = {
			/** String vars **/
			bigStarsPath : 'jquery/icons/stars.png', // path of the icon stars.png
			smallStarsPath : 'jquery/icons/small.png', // path of the icon small.png
			phpPath : 'php/jRating.php', // path of the php file jRating.php
			type : 'big', // can be set to 'small' or 'big'

			/** Boolean vars **/
			step:false, // if true,  mouseover binded star by star,
			isDisabled:false,
			showRateInfo: true,

			/** Integer vars **/
			length:5, // number of star to display
			decimalLength : 0, // number of decimals.. Max 3, but you can complete the function 'getNote'
			rateMax : 20, // maximal rate - integer from 0 to 9999 (or more)
			rateInfosX : -45, // relative position in X axis of the info box when mouseover
			rateInfosY : 5, // relative position in Y axis of the info box when mouseover

			/** Functions **/
			onSuccess : null,
			onError : null
		};

		if(this.length>0)
		return this.each(function() {
			var opts = $.extend(defaults, op),
			newWidth = 0,
			starWidth = 0,
			starHeight = 0,
			bgPath = '';

			if($(this).hasClass('jDisabled') || opts.isDisabled)
				var jDisabled = true;
			else
				var jDisabled = false;

			getStarWidth();
			$(this).height(starHeight);

			var average = parseFloat($(this).attr('id').split('_')[0]),
			idBox = parseInt($(this).attr('id').split('_')[1]), // get the id of the box
			widthRatingContainer = starWidth*opts.length, // Width of the Container
			widthColor = average/opts.rateMax*widthRatingContainer, // Width of the color Container

			quotient =
			$('
',
			{
				'class' : 'jRatingColor',
				css:{
					width:widthColor
				}
			}).appendTo($(this)),

			average =
			$('
',
			{
				'class' : 'jRatingAverage',
				css:{
					width:0,
					top:- starHeight
				}
			}).appendTo($(this)),

			 jstar =
			$('
',
			{
				'class' : 'jStar',
				css:{
					width:widthRatingContainer,
					height:starHeight,
					top:- (starHeight*2),
					background: 'url('+bgPath+') repeat-x'
				}
			}).appendTo($(this));

			$(this).css({width: widthRatingContainer,overflow:'hidden',zIndex:1,position:'relative'});

			if(!jDisabled)
			$(this).bind({
				mouseenter : function(e){
					var realOffsetLeft = findRealLeft(this);
					var relativeX = e.pageX - realOffsetLeft;
					if (opts.showRateInfo)
					var tooltip =
					$('
',{
						'class' : 'jRatingInfos',
						html : getNote(relativeX)+' / '+opts.rateMax+'',
						css : {
							top: (e.pageY + opts.rateInfosY),
							left: (e.pageX + opts.rateInfosX)
						}
					}).appendTo('body').show();
				},
				mouseover : function(e){
					$(this).css('cursor','pointer');
				},
				mouseout : function(){
					$(this).css('cursor','default');
					average.width(0);
				},
				mousemove : function(e){
					var realOffsetLeft = findRealLeft(this);
					var relativeX = e.pageX - realOffsetLeft;
					if(opts.step) newWidth = Math.floor(relativeX/starWidth)*starWidth + starWidth;
					else newWidth = relativeX;
					average.width(newWidth);
					if (opts.showRateInfo)
					$("p.jRatingInfos")
					.css({
						left: (e.pageX + opts.rateInfosX)
					})
					.html(getNote(newWidth) +' / '+opts.rateMax+'');
				},
				mouseleave : function(){
					$("p.jRatingInfos").remove();
				},
				click : function(e){
					$(this).unbind().css('cursor','default').addClass('jDisabled');
					if (opts.showRateInfo) $("p.jRatingInfos").fadeOut('fast',function(){$(this).remove();});
					e.preventDefault();
					var rate = getNote(newWidth);
					average.width(newWidth);

					/** ONLY FOR THE DEMO, YOU CAN REMOVE THIS CODE **/
						$('.datasSent p').html('idBox : '+idBox+'
rate : '+rate+'
action : rating');
						$('.serverResponse p').html('Loading...');
					/** END ONLY FOR THE DEMO **/

					$.post(opts.phpPath,{
							idBox : idBox,
							rate : rate,
							action : 'rating'
						},
						function(data) {
							if(!data.error)
							{
								/** ONLY FOR THE DEMO, YOU CAN REMOVE THIS CODE **/
									$('.serverResponse p').html(data.server);
								/** END ONLY FOR THE DEMO **/

								/** Here you can display an alert box,
									or use the jNotify Plugin :) http://www.myqjqueryplugins.com/jNotify
									exemple :	*/
								if(opts.onSuccess) opts.onSuccess();
							}
							else
							{

								/** ONLY FOR THE DEMO, YOU CAN REMOVE THIS CODE **/
									$('.serverResponse p').html(data.server);
								/** END ONLY FOR THE DEMO **/

								/** Here you can display an alert box,
									or use the jNotify Plugin :) http://www.myqjqueryplugins.com/jNotify
									exemple :	*/
								if(opts.onError) opts.onError();
							}
						},
						'json'
					);
				}
			});

			function getNote(relativeX) {
				var noteBrut = parseFloat((relativeX*100/widthRatingContainer)*opts.rateMax/100);
				switch(opts.decimalLength) {
					case 1 :
						var note = Math.round(noteBrut*10)/10;
						break;
					case 2 :
						var note = Math.round(noteBrut*100)/100;
						break;
					case 3 :
						var note = Math.round(noteBrut*1000)/1000;
						break;
					default :
						var note = Math.round(noteBrut*1)/1;
				}
				return note;
			};

			function getStarWidth(){
				switch(opts.type) {
					case 'small' :
						starWidth = 12; // width of the picture small.png
						starHeight = 10; // height of the picture small.png
						bgPath = opts.smallStarsPath;
					break;
					default :
						starWidth = 23; // width of the picture stars.png
						starHeight = 20; // height of the picture stars.png
						bgPath = opts.bigStarsPath;
				}
			};

			function findRealLeft(obj) {
			  if( !obj ) return 0;
			  return obj.offsetLeft + findRealLeft( obj.offsetParent );
			};
		});

	}
})(jQuery);<commit_msg>modifs<commit_after>/************************************************************************
*************************************************************************
@Name :       	jRating - jQuery Plugin
@Revison :    	2.2
@Date : 		26/01/2011
@Author:     	 ALPIXEL - (www.myjqueryplugins.com - www.alpixel.fr)
@License :		 Open Source - MIT License : http://www.opensource.org/licenses/mit-license.php

**************************************************************************
*************************************************************************/
(function($) {
	$.fn.jRating = function(op) {
		var defaults = {
			/** String vars **/
			bigStarsPath : 'jquery/icons/stars.png', // path of the icon stars.png
			smallStarsPath : 'jquery/icons/small.png', // path of the icon small.png
			phpPath : 'php/jRating.php', // path of the php file jRating.php
			type : 'big', // can be set to 'small' or 'big'

			/** Boolean vars **/
			step:false, // if true,  mouseover binded star by star,
			isDisabled:false,
			showRateInfo: true,

			/** Integer vars **/
			length:5, // number of star to display
			decimalLength : 0, // number of decimals.. Max 3, but you can complete the function 'getNote'
			rateMax : 20, // maximal rate - integer from 0 to 9999 (or more)
			rateInfosX : -45, // relative position in X axis of the info box when mouseover
			rateInfosY : 5, // relative position in Y axis of the info box when mouseover

			/** Functions **/
			onSuccess : null,
			onError : null
		};

		if(this.length>0)
		return this.each(function() {
			var opts = $.extend(defaults, op),
			newWidth = 0,
			starWidth = 0,
			starHeight = 0,
			bgPath = '';

			if($(this).hasClass('jDisabled') || opts.isDisabled)
				var jDisabled = true;
			else
				var jDisabled = false;

			getStarWidth();
			$(this).height(starHeight);

			var average = parseFloat($(this).attr('id').split('_')[0]),
			idBox = parseInt($(this).attr('id').split('_')[1]), // get the id of the box
			widthRatingContainer = starWidth*opts.length, // Width of the Container
			widthColor = average/opts.rateMax*widthRatingContainer, // Width of the color Container

			quotient =
			$('
',
			{
				'class' : 'jRatingColor',
				css:{
					width:widthColor
				}
			}).appendTo($(this)),

			average =
			$('
',
			{
				'class' : 'jRatingAverage',
				css:{
					width:0,
					top:- starHeight
				}
			}).appendTo($(this)),

			 jstar =
			$('
',
			{
				'class' : 'jStar',
				css:{
					width:widthRatingContainer,
					height:starHeight,
					top:- (starHeight*2),
					background: 'url('+bgPath+') repeat-x'
				}
			}).appendTo($(this));

			$(this).css({width: widthRatingContainer,overflow:'hidden',zIndex:1,position:'relative'});

			if(!jDisabled)
			$(this).unbind().bind({
				mouseenter : function(e){
					var realOffsetLeft = findRealLeft(this);
					var relativeX = e.pageX - realOffsetLeft;
					if (opts.showRateInfo)
					var tooltip =
					$('
',{
						'class' : 'jRatingInfos',
						html : getNote(relativeX)+' / '+opts.rateMax+'',
						css : {
							top: (e.pageY + opts.rateInfosY),
							left: (e.pageX + opts.rateInfosX)
						}
					}).appendTo('body').show();
				},
				mouseover : function(e){
					$(this).css('cursor','pointer');
				},
				mouseout : function(){
					$(this).css('cursor','default');
					average.width(0);
				},
				mousemove : function(e){
					var realOffsetLeft = findRealLeft(this);
					var relativeX = e.pageX - realOffsetLeft;
					if(opts.step) newWidth = Math.floor(relativeX/starWidth)*starWidth + starWidth;
					else newWidth = relativeX;
					average.width(newWidth);
					if (opts.showRateInfo)
					$("p.jRatingInfos")
					.css({
						left: (e.pageX + opts.rateInfosX)
					})
					.html(getNote(newWidth) +' / '+opts.rateMax+'');
				},
				mouseleave : function(){
					$("p.jRatingInfos").remove();
				},
				click : function(e){
                    var element = this;
					$(this).unbind().css('cursor','default').addClass('jDisabled');
					if (opts.showRateInfo) $("p.jRatingInfos").fadeOut('fast',function(){$(this).remove();});
					e.preventDefault();
					var rate = getNote(newWidth);
					average.width(newWidth);

					/** ONLY FOR THE DEMO, YOU CAN REMOVE THIS CODE **/
						$('.datasSent p').html('idBox : '+idBox+'
rate : '+rate+'
action : rating');
						$('.serverResponse p').html('Loading...');
					/** END ONLY FOR THE DEMO **/

					$.post(opts.phpPath,{
							idBox : idBox,
							rate : rate,
							action : 'rating'
						},
						function(data) {
							if(!data.error)
							{
								/** ONLY FOR THE DEMO, YOU CAN REMOVE THIS CODE **/
									$('.serverResponse p').html(data.server);
								/** END ONLY FOR THE DEMO **/

								/** Here you can display an alert box,
									or use the jNotify Plugin :) http://www.myqjqueryplugins.com/jNotify
									exemple :	*/
								if(opts.onSuccess) opts.onSuccess( element, rate );
							}
							else
							{

								/** ONLY FOR THE DEMO, YOU CAN REMOVE THIS CODE **/
									$('.serverResponse p').html(data.server);
								/** END ONLY FOR THE DEMO **/

								/** Here you can display an alert box,
									or use the jNotify Plugin :) http://www.myqjqueryplugins.com/jNotify
									exemple :	*/
								if(opts.onError) opts.onError( element, rate );
							}
						},
						'json'
					);
				}
			});

			function getNote(relativeX) {
				var noteBrut = parseFloat((relativeX*100/widthRatingContainer)*opts.rateMax/100);
				switch(opts.decimalLength) {
					case 1 :
						var note = Math.round(noteBrut*10)/10;
						break;
					case 2 :
						var note = Math.round(noteBrut*100)/100;
						break;
					case 3 :
						var note = Math.round(noteBrut*1000)/1000;
						break;
					default :
						var note = Math.round(noteBrut*1)/1;
				}
				return note;
			};

			function getStarWidth(){
				switch(opts.type) {
					case 'small' :
						starWidth = 12; // width of the picture small.png
						starHeight = 10; // height of the picture small.png
						bgPath = opts.smallStarsPath;
					break;
					default :
						starWidth = 23; // width of the picture stars.png
						starHeight = 20; // height of the picture stars.png
						bgPath = opts.bigStarsPath;
				}
			};

			function findRealLeft(obj) {
			  if( !obj ) return 0;
			  return obj.offsetLeft + findRealLeft( obj.offsetParent );
			};
		});

	}
})(jQuery);<|endoftext|>


<commit_before>// Copyright 2013-2015, University of Colorado Boulder

/**
 * Main entry point for the 'Fraction Matcher sim.
 *
 * @author Anton Ulyanov, Andrew Zelenkov (Mlearner)
 */

define( function( require ) {
  'use strict';

  // modules
  var Screen = require( 'JOIST/Screen' );
  var FractionMatcherModel = require( 'FRACTION_MATCHER/model/FractionMatcherModel' );
  var FractionMatcherView = require( 'FRACTION_MATCHER/view/FractionMatcherView' );
  var MixedNumbersConstants = require( 'FRACTION_MATCHER/model/MixedNumbersConstants' );
  var MixedNumbersHomeScreenIcon = require( 'FRACTION_MATCHER/view/MixedNumbersHomeScreenIcon' );
  var MixedNumbersNavigationBarIcon = require( 'FRACTION_MATCHER/view/MixedNumbersNavigationBarIcon' );
  var inherit = require( 'PHET_CORE/inherit' );

  // strings
  var mixedNumbersTitleString = require( 'string!FRACTION_MATCHER/mixedNumbersTitle' );

  function MixedNumbersScreen() {
    Screen.call( this, mixedNumbersTitleString, new MixedNumbersHomeScreenIcon(),
      function() { return new FractionMatcherModel( FractionMatcherView.LAYOUT_BOUNDS.width, FractionMatcherView.LAYOUT_BOUNDS.height, mixedNumbersTitleString, new MixedNumbersConstants(), true ); },
      function( model ) { return new FractionMatcherView( model ); },
      {
        navigationBarIcon: new MixedNumbersNavigationBarIcon()
      } );
  }

  return inherit( Screen, MixedNumbersScreen );
} );<commit_msg>Doc change<commit_after>// Copyright 2013-2015, University of Colorado Boulder

/**
 * Main entry point for the 'Fraction Matcher sim.
 *
 * @author Anton Ulyanov
 * @author Andrew Zelenkov (Mlearner)
 * @author Sam Reid (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var Screen = require( 'JOIST/Screen' );
  var FractionMatcherModel = require( 'FRACTION_MATCHER/model/FractionMatcherModel' );
  var FractionMatcherView = require( 'FRACTION_MATCHER/view/FractionMatcherView' );
  var MixedNumbersConstants = require( 'FRACTION_MATCHER/model/MixedNumbersConstants' );
  var MixedNumbersHomeScreenIcon = require( 'FRACTION_MATCHER/view/MixedNumbersHomeScreenIcon' );
  var MixedNumbersNavigationBarIcon = require( 'FRACTION_MATCHER/view/MixedNumbersNavigationBarIcon' );
  var inherit = require( 'PHET_CORE/inherit' );

  // strings
  var mixedNumbersTitleString = require( 'string!FRACTION_MATCHER/mixedNumbersTitle' );

  function MixedNumbersScreen() {
    Screen.call( this, mixedNumbersTitleString, new MixedNumbersHomeScreenIcon(),
      function() { return new FractionMatcherModel( FractionMatcherView.LAYOUT_BOUNDS.width, FractionMatcherView.LAYOUT_BOUNDS.height, mixedNumbersTitleString, new MixedNumbersConstants(), true ); },
      function( model ) { return new FractionMatcherView( model ); },
      {
        navigationBarIcon: new MixedNumbersNavigationBarIcon()
      } );
  }

  return inherit( Screen, MixedNumbersScreen );
} );<|endoftext|>


<commit_before>import React from 'react'
import Document, {Head, Main} from 'next/document'
import {renderStatic} from 'glamor/server'
import GoogleAnalytics from '../../components/google-analytics'
import ConsoleGreet from '../../components/console-greet'
import content from './content'

export default class MyDocument extends Document {
  static getInitialProps({renderPage}) {
    const page = renderPage()
    const styles = renderStatic(() => page.html)
    const locale = process.env.LOCALE
    return Promise.resolve({...page, ...styles, locale})
  }

  constructor(props) {
    super(props)
    const {__NEXT_DATA__, ids} = props
    if (ids) {
      __NEXT_DATA__.ids = this.props.ids
    }
  }

  render() {
    return (
      <html lang={this.props.locale}>
        <Head>
          <title>
            {content.title}
          </title>
          <style dangerouslySetInnerHTML={{__html: this.props.css}} />
          <meta name="viewport" content="width=device-width, initial-scale=1" />
          <link
            rel="shortcut icon"
            type="image/x-icon"
            href="/static/images/icon.png"
          />
        </Head>
        <body>
          <Main />
          <GoogleAnalytics />
          <ConsoleGreet />
        </body>
      </html>
    )
  }
}
<commit_msg>fix sit...<commit_after>import React from 'react'
import Document, {Head, Main, NextScript} from 'next/document'
import {renderStatic} from 'glamor/server'
import GoogleAnalytics from '../../components/google-analytics'
import ConsoleGreet from '../../components/console-greet'
import content from './content'

export default class MyDocument extends Document {
  static getInitialProps({renderPage}) {
    const page = renderPage()
    const styles = renderStatic(() => page.html)
    const locale = process.env.LOCALE
    return Promise.resolve({...page, ...styles, locale})
  }

  constructor(props) {
    super(props)
    const {__NEXT_DATA__, ids} = props
    if (ids) {
      __NEXT_DATA__.ids = this.props.ids
    }
  }

  render() {
    return (
      <html lang={this.props.locale}>
        <Head>
          <title>
            {content.title}
          </title>
          <style dangerouslySetInnerHTML={{__html: this.props.css}} />
          <meta name="viewport" content="width=device-width, initial-scale=1" />
          <link
            rel="shortcut icon"
            type="image/x-icon"
            href="/static/images/icon.png"
          />
        </Head>
        <body>
          <Main />
          <NextScript />
          <GoogleAnalytics />
          <ConsoleGreet />
        </body>
      </html>
    )
  }
}
<|endoftext|>


<commit_before>/**
 * Created by alo on 5/9/15.
 */
var e_openCurlyBraces = '{';
var e_closeCurlyBraces = '}';
var e_colon = ':';
var e_plus = '+';
var e_equals = '=';
var e_pipe = '|';

var panel = {};

var referenceToExpression = function(conceptReference) {
    return conceptReference.conceptId + " " + e_pipe + "" +
        conceptReference.defaultTerm + "" + e_pipe;
};

var conceptToPostCoordinatedExpression = function(concept, relsProperty, div, options) {
    var expression = "";
    var tab = "    ";
    if (concept.definitionStatus == "Fully defined" || concept.definitionStatus == "Sufficiently defined") {
        expression += "=== ";
    } else {
        expression += "<<< ";
    }
    if (concept[relsProperty] && concept[relsProperty].length > 0) {
        //expression += ' {';
        var firstParent = true;
        var attributes = {};
        $.each(concept[relsProperty], function(i, rel){
            if (rel.active == true && rel.type.conceptId == "116680003") {
                if (!firstParent) {
                    expression += " " + e_plus + "
";
                    expression += tab + referenceToExpression(rel.target);
                } else {
                    expression += referenceToExpression(rel.target);
                }
                firstParent = false;

            } else if (rel.active == true && rel.type.conceptId != "116680003") {
                if (!attributes[rel.groupId]) {
                    attributes[rel.groupId] = [];
                }
                attributes[rel.groupId].push(rel);
            }
        });
        //console.log(attributes);
        var groups = Object.keys(attributes);
        if (groups.length > 0) {
            expression += " " + e_colon;
        }
        $.each(groups, function(i, group){
            expression += "
";

            var firstInGroup = true;
            $.each(attributes[group], function(i, rel){
                if (!firstInGroup) {
                    expression += ",
";
                }
                if (group > 0) {
                    expression += tab + tab + tab;
                } else {
                    expression += tab + tab;
                }
                if (firstInGroup && group > 0) {
                    expression += e_openCurlyBraces + " ";
                } else if (group > 0){
                    expression += "  ";
                }
                firstInGroup = false;
                expression += referenceToExpression(rel.type) + " " + e_equals + " " + referenceToExpression(rel.target);
            });
            if (group != 0) {
                expression += " " + e_closeCurlyBraces;
            }
        });
    }
    return expression;
};

function formatOwlAxiomExpression (owlExpression, conceptsMap) {
    var text = owlExpression;

    // Add new line char
    text = text.replace(/\(/g, "(\n");
    text = text.replace(/\)/g, "\n)\n");
    text = text.replace(/(?<=:\d*)\s/g, "\n");
    text = text.replace(/(?<=:roleGroup)\s/g, "\n");

    var textArr = text.split("\n");
    textArr = textArr.filter(function (el) {
      el = el.trim();
      return el != '';
    });

    // Add tab char
    var tabCount = 0;
    for (var i = 0 ; i < textArr.length; i++) {
      textArr[i] = textArr[i].trim();
      if (textArr[i].indexOf(')') !== -1) {
        tabCount--;
      }
      if (i !== 0 && tabCount > 0) {
        for (var j = 0 ; j < tabCount; j++) {
          textArr[i] = '\t' + textArr[i];
        }
      }
      if (textArr[i].indexOf('(') !== -1) {
        tabCount++;
      }

      // Fill FSN
      textArr[i] = fillConceptFSN(textArr[i], conceptsMap);
    }
    return textArr.join('\n');
}

function fillConceptFSN (text, conceptsMap) {
    var tempStr = text.trim();
    if (tempStr.indexOf(':roleGroup') != -1) {
      return text.replace(':roleGroup', ':609096000 |Role group (attribute)|');
    } else {
      const match = /(^:\d*)/g;
      if (match.test(tempStr)) {
        var conceptId = tempStr.substring(1,tempStr.length);
        if (conceptsMap.hasOwnProperty(conceptId)) {
          return text + ' |' + conceptsMap[conceptId] + '|';
        } else {
          return text;
        }
      } else {
        return text;
      }
    }
}

function renderExpressionForAxioms (concept, members, classAxiomOwlExpressions, gciAxiomOwlExpressions) {
    var owlAxiomExpressions = {};

    members.forEach(function(item) {
        if (item.additionalFields.hasOwnProperty('owlExpression')) {
            if(item.memberId){
                owlAxiomExpressions[item.memberId] = item.additionalFields['owlExpression'];
            }
            else{
                owlAxiomExpressions[item.id] = item.additionalFields['owlExpression'];
            }
        }
    });

    var conceptsMap = {};
    conceptsMap[concept.conceptId] = concept.fsn.term;
    conceptsMap[609096000] = 'Role group (attribute)';
    conceptsMap[116680003] = 'Is a (attribute)';

    if(concept.classAxioms && concept.classAxioms.length !== 0) {
        concept.classAxioms.forEach(function(classAxiom){
            classAxiom.relationships.forEach(function(relationship){
                conceptsMap[relationship.type.conceptId] = relationship.type.fsn.term;
                conceptsMap[relationship.target.conceptId] = relationship.target.fsn.term;
        });
        });
    }

    if(concept.gciAxioms && concept.gciAxioms.length !== 0) {
        concept.gciAxioms.forEach(function(classAxiom){
            classAxiom.relationships.forEach(function(relationship){
                conceptsMap[relationship.type.conceptId] = relationship.type.fsn.term;
                conceptsMap[relationship.target.conceptId] = relationship.target.fsn.term;
        });
        });
    }

    var owlAxiomExpression = {};
    for (var key in owlAxiomExpressions) {
        owlAxiomExpression[key] = formatOwlAxiomExpression(owlAxiomExpressions[key], conceptsMap);
    }

    if(concept.classAxioms && concept.classAxioms.length !== 0) {
        concept.classAxioms.forEach(function(classAxiom){
            if (owlAxiomExpression.hasOwnProperty(classAxiom.axiomId)) {
                classAxiomOwlExpressions.push(owlAxiomExpression[classAxiom.axiomId]);
            }
        });
    }

    if(concept.gciAxioms && concept.gciAxioms.length !== 0) {
        concept.gciAxioms.forEach(function(classAxiom){
            if (owlAxiomExpression.hasOwnProperty(classAxiom.axiomId)) {
                gciAxiomOwlExpressions.push(owlAxiomExpression[classAxiom.axiomId]);
            }
        });
    }
}

var renderExpression = function(concept, inferredConcept, div, options) {
    var preCoordinatedHtml = referenceToExpression(concept);
    var tmp = document.createElement("DIV");
    tmp.innerHTML = preCoordinatedHtml;
    var plainPreCoordinatedExpression =  tmp.textContent || tmp.innerText || "";
    plainPreCoordinatedExpression = plainPreCoordinatedExpression.replace(/\s\s+/g, ' ');

    if(concept.classAxioms || concept.gciAxioms) {

        $.getJSON(options.serverUrl + "/" + options.edition + "/" + ((options.release && options.release !== 'None') ? options.release + '/': '') + "members?referencedComponentId=" + concept.conceptId + '&active=true', function(result) {
        }).done(function(result) {
            var classAxiomOwlExpressions = [];
            var gciAxiomOwlExpressions = [];
            if (result.total > 0) {
                renderExpressionForAxioms (concept, result.items, classAxiomOwlExpressions, gciAxiomOwlExpressions)
            }

            var inferredHtml = conceptToPostCoordinatedExpression(concept, "relationships", div, options);
            var tmp = document.createElement("DIV");
            tmp.innerHTML = inferredHtml;
            var plainInferredExpression =  tmp.textContent || tmp.innerText || "";
            plainInferredExpression = plainInferredExpression.replace(/\s\s+/g, ' ');

            var context = {
                divElementId: div.attr('id'),
                preCoordinatedExpressionHtml: preCoordinatedHtml,
                statedExpressionHtml: '',
                inferredExpressionHtml: inferredHtml,
                plainPreCoordinatedExpression: plainPreCoordinatedExpression,
                plainStatedExpression: plainStatedExpression,
                classAxiomOwlExpressions: classAxiomOwlExpressions,
                gciAxiomOwlExpressions: gciAxiomOwlExpressions,
                plainInferredExpression: plainInferredExpression
            };
            div.html(JST["views/conceptDetailsPlugin/tabs/expression.hbs"](context).trim());

            if (panel.clipboard) panel.clipboard.destroy();
            panel.clipboard = new Clipboard('.clip-btn-exp');
            panel.clipboard.on('success', function(e) {
                // console.info('Action:', e.action);
                // console.info('Text:', e.text);
                // console.info('Trigger:', e.trigger);
                alertEvent("Copied!", "info");
                e.clearSelection();
            });
            panel.clipboard.on('error', function(e) {
                console.log("Error!");
                alertEvent("Error", "error");
            });
        });
    } else {
        var statedHtml = conceptToPostCoordinatedExpression(concept, "statedRelationships");
        var tmp = document.createElement("DIV");
        tmp.innerHTML = statedHtml;
        var plainStatedExpression =  tmp.textContent || tmp.innerText || "";
        plainStatedExpression = plainStatedExpression.replace(/\s\s+/g, ' ');

        var inferredHtml = conceptToPostCoordinatedExpression(concept, "relationships", div, options);
        var tmp = document.createElement("DIV");
        tmp.innerHTML = inferredHtml;
        var plainInferredExpression =  tmp.textContent || tmp.innerText || "";
        plainInferredExpression = plainInferredExpression.replace(/\s\s+/g, ' ');

        var context = {
            divElementId: div.attr('id'),
            preCoordinatedExpressionHtml: preCoordinatedHtml,
            statedExpressionHtml: statedHtml,
            inferredExpressionHtml: inferredHtml,
            plainPreCoordinatedExpression: plainPreCoordinatedExpression,
            plainStatedExpression: plainStatedExpression,
            classAxiomOwlExpressions: [],
            gciAxiomOwlExpressions: [],
            plainInferredExpression: plainInferredExpression
        };
        div.html(JST["views/conceptDetailsPlugin/tabs/expression.hbs"](context).trim());

        if (panel.clipboard) panel.clipboard.destroy();
        panel.clipboard = new Clipboard('.clip-btn-exp');
        panel.clipboard.on('success', function(e) {
            // console.info('Action:', e.action);
            // console.info('Text:', e.text);
            // console.info('Trigger:', e.trigger);
            alertEvent("Copied!", "info");
            e.clearSelection();
        });
        panel.clipboard.on('error', function(e) {
            console.log("Error!");
            alertEvent("Error", "error");
        });
    }
};
<commit_msg>BROWSE-202 check empty list<commit_after>/**
 * Created by alo on 5/9/15.
 */
var e_openCurlyBraces = '{';
var e_closeCurlyBraces = '}';
var e_colon = ':';
var e_plus = '+';
var e_equals = '=';
var e_pipe = '|';

var panel = {};

var referenceToExpression = function(conceptReference) {
    return conceptReference.conceptId + " " + e_pipe + "" +
        conceptReference.defaultTerm + "" + e_pipe;
};

var conceptToPostCoordinatedExpression = function(concept, relsProperty, div, options) {
    var expression = "";
    var tab = "    ";
    if (concept.definitionStatus == "Fully defined" || concept.definitionStatus == "Sufficiently defined") {
        expression += "=== ";
    } else {
        expression += "<<< ";
    }
    if (concept[relsProperty] && concept[relsProperty].length > 0) {
        //expression += ' {';
        var firstParent = true;
        var attributes = {};
        $.each(concept[relsProperty], function(i, rel){
            if (rel.active == true && rel.type.conceptId == "116680003") {
                if (!firstParent) {
                    expression += " " + e_plus + "
";
                    expression += tab + referenceToExpression(rel.target);
                } else {
                    expression += referenceToExpression(rel.target);
                }
                firstParent = false;

            } else if (rel.active == true && rel.type.conceptId != "116680003") {
                if (!attributes[rel.groupId]) {
                    attributes[rel.groupId] = [];
                }
                attributes[rel.groupId].push(rel);
            }
        });
        //console.log(attributes);
        var groups = Object.keys(attributes);
        if (groups.length > 0) {
            expression += " " + e_colon;
        }
        $.each(groups, function(i, group){
            expression += "
";

            var firstInGroup = true;
            $.each(attributes[group], function(i, rel){
                if (!firstInGroup) {
                    expression += ",
";
                }
                if (group > 0) {
                    expression += tab + tab + tab;
                } else {
                    expression += tab + tab;
                }
                if (firstInGroup && group > 0) {
                    expression += e_openCurlyBraces + " ";
                } else if (group > 0){
                    expression += "  ";
                }
                firstInGroup = false;
                expression += referenceToExpression(rel.type) + " " + e_equals + " " + referenceToExpression(rel.target);
            });
            if (group != 0) {
                expression += " " + e_closeCurlyBraces;
            }
        });
    }
    return expression;
};

function formatOwlAxiomExpression (owlExpression, conceptsMap) {
    var text = owlExpression;

    // Add new line char
    text = text.replace(/\(/g, "(\n");
    text = text.replace(/\)/g, "\n)\n");
    text = text.replace(/(?<=:\d*)\s/g, "\n");
    text = text.replace(/(?<=:roleGroup)\s/g, "\n");

    var textArr = text.split("\n");
    textArr = textArr.filter(function (el) {
      el = el.trim();
      return el != '';
    });

    // Add tab char
    var tabCount = 0;
    for (var i = 0 ; i < textArr.length; i++) {
      textArr[i] = textArr[i].trim();
      if (textArr[i].indexOf(')') !== -1) {
        tabCount--;
      }
      if (i !== 0 && tabCount > 0) {
        for (var j = 0 ; j < tabCount; j++) {
          textArr[i] = '\t' + textArr[i];
        }
      }
      if (textArr[i].indexOf('(') !== -1) {
        tabCount++;
      }

      // Fill FSN
      textArr[i] = fillConceptFSN(textArr[i], conceptsMap);
    }
    return textArr.join('\n');
}

function fillConceptFSN (text, conceptsMap) {
    var tempStr = text.trim();
    if (tempStr.indexOf(':roleGroup') != -1) {
      return text.replace(':roleGroup', ':609096000 |Role group (attribute)|');
    } else {
      const match = /(^:\d*)/g;
      if (match.test(tempStr)) {
        var conceptId = tempStr.substring(1,tempStr.length);
        if (conceptsMap.hasOwnProperty(conceptId)) {
          return text + ' |' + conceptsMap[conceptId] + '|';
        } else {
          return text;
        }
      } else {
        return text;
      }
    }
}

function renderExpressionForAxioms (concept, members, classAxiomOwlExpressions, gciAxiomOwlExpressions) {
    var owlAxiomExpressions = {};

    members.forEach(function(item) {
        if (item.additionalFields.hasOwnProperty('owlExpression')) {
            if(item.memberId){
                owlAxiomExpressions[item.memberId] = item.additionalFields['owlExpression'];
            }
            else{
                owlAxiomExpressions[item.id] = item.additionalFields['owlExpression'];
            }
        }
    });

    var conceptsMap = {};
    conceptsMap[concept.conceptId] = concept.fsn.term;
    conceptsMap[609096000] = 'Role group (attribute)';
    conceptsMap[116680003] = 'Is a (attribute)';

    if(concept.classAxioms && concept.classAxioms.length !== 0) {
        concept.classAxioms.forEach(function(classAxiom){
            classAxiom.relationships.forEach(function(relationship){
                conceptsMap[relationship.type.conceptId] = relationship.type.fsn.term;
                conceptsMap[relationship.target.conceptId] = relationship.target.fsn.term;
        });
        });
    }

    if(concept.gciAxioms && concept.gciAxioms.length !== 0) {
        concept.gciAxioms.forEach(function(classAxiom){
            classAxiom.relationships.forEach(function(relationship){
                conceptsMap[relationship.type.conceptId] = relationship.type.fsn.term;
                conceptsMap[relationship.target.conceptId] = relationship.target.fsn.term;
        });
        });
    }

    var owlAxiomExpression = {};
    for (var key in owlAxiomExpressions) {
        owlAxiomExpression[key] = formatOwlAxiomExpression(owlAxiomExpressions[key], conceptsMap);
    }

    if(concept.classAxioms && concept.classAxioms.length !== 0) {
        concept.classAxioms.forEach(function(classAxiom){
            if (owlAxiomExpression.hasOwnProperty(classAxiom.axiomId)) {
                classAxiomOwlExpressions.push(owlAxiomExpression[classAxiom.axiomId]);
            }
        });
    }

    if(concept.gciAxioms && concept.gciAxioms.length !== 0) {
        concept.gciAxioms.forEach(function(classAxiom){
            if (owlAxiomExpression.hasOwnProperty(classAxiom.axiomId)) {
                gciAxiomOwlExpressions.push(owlAxiomExpression[classAxiom.axiomId]);
            }
        });
    }
}

var renderExpression = function(concept, inferredConcept, div, options) {
    var preCoordinatedHtml = referenceToExpression(concept);
    var tmp = document.createElement("DIV");
    tmp.innerHTML = preCoordinatedHtml;
    var plainPreCoordinatedExpression =  tmp.textContent || tmp.innerText || "";
    plainPreCoordinatedExpression = plainPreCoordinatedExpression.replace(/\s\s+/g, ' ');

    if((concept.classAxioms && concept.classAxioms.length !== 0) || concept.gciAxioms && concept.gciAxioms.length !== 0) {

        $.getJSON(options.serverUrl + "/" + options.edition + "/" + ((options.release && options.release !== 'None') ? options.release + '/': '') + "members?referencedComponentId=" + concept.conceptId + '&active=true', function(result) {
        }).done(function(result) {
            var classAxiomOwlExpressions = [];
            var gciAxiomOwlExpressions = [];
            if (result.total > 0) {
                renderExpressionForAxioms (concept, result.items, classAxiomOwlExpressions, gciAxiomOwlExpressions)
            }

            var inferredHtml = conceptToPostCoordinatedExpression(concept, "relationships", div, options);
            var tmp = document.createElement("DIV");
            tmp.innerHTML = inferredHtml;
            var plainInferredExpression =  tmp.textContent || tmp.innerText || "";
            plainInferredExpression = plainInferredExpression.replace(/\s\s+/g, ' ');

            var context = {
                divElementId: div.attr('id'),
                preCoordinatedExpressionHtml: preCoordinatedHtml,
                statedExpressionHtml: '',
                inferredExpressionHtml: inferredHtml,
                plainPreCoordinatedExpression: plainPreCoordinatedExpression,
                plainStatedExpression: plainStatedExpression,
                classAxiomOwlExpressions: classAxiomOwlExpressions,
                gciAxiomOwlExpressions: gciAxiomOwlExpressions,
                plainInferredExpression: plainInferredExpression
            };
            div.html(JST["views/conceptDetailsPlugin/tabs/expression.hbs"](context).trim());

            if (panel.clipboard) panel.clipboard.destroy();
            panel.clipboard = new Clipboard('.clip-btn-exp');
            panel.clipboard.on('success', function(e) {
                // console.info('Action:', e.action);
                // console.info('Text:', e.text);
                // console.info('Trigger:', e.trigger);
                alertEvent("Copied!", "info");
                e.clearSelection();
            });
            panel.clipboard.on('error', function(e) {
                console.log("Error!");
                alertEvent("Error", "error");
            });
        });
    } else {
        var statedHtml = conceptToPostCoordinatedExpression(concept, "statedRelationships");
        var tmp = document.createElement("DIV");
        tmp.innerHTML = statedHtml;
        var plainStatedExpression =  tmp.textContent || tmp.innerText || "";
        plainStatedExpression = plainStatedExpression.replace(/\s\s+/g, ' ');

        var inferredHtml = conceptToPostCoordinatedExpression(concept, "relationships", div, options);
        var tmp = document.createElement("DIV");
        tmp.innerHTML = inferredHtml;
        var plainInferredExpression =  tmp.textContent || tmp.innerText || "";
        plainInferredExpression = plainInferredExpression.replace(/\s\s+/g, ' ');

        var context = {
            divElementId: div.attr('id'),
            preCoordinatedExpressionHtml: preCoordinatedHtml,
            statedExpressionHtml: statedHtml,
            inferredExpressionHtml: inferredHtml,
            plainPreCoordinatedExpression: plainPreCoordinatedExpression,
            plainStatedExpression: plainStatedExpression,
            classAxiomOwlExpressions: [],
            gciAxiomOwlExpressions: [],
            plainInferredExpression: plainInferredExpression
        };
        div.html(JST["views/conceptDetailsPlugin/tabs/expression.hbs"](context).trim());

        if (panel.clipboard) panel.clipboard.destroy();
        panel.clipboard = new Clipboard('.clip-btn-exp');
        panel.clipboard.on('success', function(e) {
            // console.info('Action:', e.action);
            // console.info('Text:', e.text);
            // console.info('Trigger:', e.trigger);
            alertEvent("Copied!", "info");
            e.clearSelection();
        });
        panel.clipboard.on('error', function(e) {
            console.log("Error!");
            alertEvent("Error", "error");
        });
    }
};
<|endoftext|>


<commit_before>require('is-nan').shim()
import Promise from 'promise-polyfill'

import {h} from 'react-markup'
import ReactDOM from 'react-dom'

import {createStore} from '~/shared/redux-helpers'
import I18N from './i18n'
import {Provider} from 'react-redux'
import {
    reducer as donateModalReducer,
    initialState as donateModalInitialState,
} from './react/reducers/donate-modal-reducer'
import Popup from '~/react/container/donate-popup'
import {
    setCurrency,
    setProvider,
    setAmount,
    setTargets,
    setFormComment,
    setShortDesc,
} from '~/react/action-creators/main-donation-form'
import {
    setModalDisplayed,
} from '~/react/action-creators/modal'

import {
    LanguageType,
    ProvideType,
    CurrencyType,
} from './shared/definitions'

/*
 Donation form and donate info
  */
new Promise((resolve) => {
    document.addEventListener('DOMContentLoaded', resolve)
}).then(() => {
    return I18N.create({
        'strings': [
            'help/donate/donate-button-title',
            'help/donate/provider-options/ym',
            'help/donate/amount-options/other-amount',
            'help/main-donation-form/money-template',
            'help/donate/info/for-us/title',
            'help/donate/info/for-them/title',
            'help/donate/info/300/for-us/options/1',
            'help/donate/info/300/for-us/options/2',
            'help/donate/info/300/for-us/options/3',
            'help/donate/info/300/for-them/options/1',
            'help/donate/info/500/for-us/options/1',
            'help/donate/info/500/for-us/options/2',
            'help/donate/info/500/for-us/options/3',
            'help/donate/info/500/for-them/options/1',
            'help/donate/info/1000/for-us/options/1',
            'help/donate/info/1000/for-us/options/2',
            'help/donate/info/1000/for-them/options/1',
            'help/donate/info/1000/for-them/options/2',
            'help/donate/info/1000/for-them/options/3',
            'help/donate/formcomment',
            'help/donate/short-dest',
            'help/donate/targets',
        ],
        'texts': [],
    })
}).then((i18n) => {
    const language = i18n.detectLanguage()

    const defaultProvider = language === LanguageType.RU ? ProvideType.YANDEX_MONEY : ProvideType.PAYPAL
    const defaultCurrency = CurrencyType[i18n.settings.language[language].defaultCurrency]

    // Init store for popup
    const popupInitialState = {
        modal: donateModalInitialState.modal,
        form: {
            ...donateModalInitialState.form,
            currencySettings: i18n.settings.currency,
        },
    }
    const popupStore = createStore(donateModalReducer, popupInitialState)
    ReactDOM.render(
        h(Provider, {store: popupStore},
            h(Popup(i18n))
        ),
        document.querySelector('#react-donate-popup-entry')
    )

    Array.prototype.slice.apply(document.querySelectorAll('.packages .package')).forEach((form) => {
        form.addEventListener('submit', (e) => {
            e.preventDefault()
            popupStore.dispatch(setProvider(defaultProvider))
            popupStore.dispatch(setCurrency(defaultCurrency))
            popupStore.dispatch(setAmount(parseInt(form.querySelector('input[name=sum]').value, 10)))
            popupStore.dispatch(setTargets(form.querySelector('input[name=formcomment]').value))
            popupStore.dispatch(setFormComment(form.querySelector('input[name=short-dest]').value))
            popupStore.dispatch(setShortDesc(form.querySelector('input[name=targets]').value))
            popupStore.dispatch(setModalDisplayed(true))
        })
    })
}).catch((e) => {
    console.error(e.stack)
})

/*
 Left menu bar
  */
const STICKY_MARGIN = 5
document.addEventListener('DOMContentLoaded', () => {
    Array.prototype.slice.apply(document.querySelectorAll('.category-menu')).forEach((menu) => {
        // Highlight current item
        const highlightItems = () => {
            Array.prototype.slice.apply(menu.querySelectorAll('.category-menu_item')).forEach((item) => {
                const url = new URL(item.getAttribute('href'), window.location)
                if (url.href === location.href) {
                    item.classList.add('category-menu_item--active')
                }
                else {
                    item.classList.remove('category-menu_item--active')
                }
            })
        }
        window.addEventListener('hashchange', highlightItems, false)
        highlightItems()

        // Make sticky menu
        const body = menu.querySelector('.category-menu_body')
        const checkSticky = () => {
            const bodyRect = document.body.getBoundingClientRect()
            const menuRect = menu.getBoundingClientRect()
            const pos = menuRect.top - bodyRect.top

            const bodyScroll = window.pageYOffset
                || document.documentElement.scrollTop
                || document.body.scrollTop || 0

            const dif = Math.max(bodyScroll - pos + STICKY_MARGIN, 0)

            body.style.top = `${dif}px`
        }
        document.addEventListener('scroll', checkSticky)
        checkSticky()
    })
})

<commit_msg>Fix sticky header<commit_after>require('is-nan').shim()
import Promise from 'promise-polyfill'

import {h} from 'react-markup'
import ReactDOM from 'react-dom'

import {createStore} from '~/shared/redux-helpers'
import I18N from './i18n'
import {Provider} from 'react-redux'
import {
    reducer as donateModalReducer,
    initialState as donateModalInitialState,
} from './react/reducers/donate-modal-reducer'
import Popup from '~/react/container/donate-popup'
import {
    setCurrency,
    setProvider,
    setAmount,
    setTargets,
    setFormComment,
    setShortDesc,
} from '~/react/action-creators/main-donation-form'
import {
    setModalDisplayed,
} from '~/react/action-creators/modal'

import {
    LanguageType,
    ProvideType,
    CurrencyType,
} from './shared/definitions'

/*
 Donation form and donate info
  */
new Promise((resolve) => {
    document.addEventListener('DOMContentLoaded', resolve)
}).then(() => {
    return I18N.create({
        'strings': [
            'help/donate/donate-button-title',
            'help/donate/provider-options/ym',
            'help/donate/amount-options/other-amount',
            'help/main-donation-form/money-template',
            'help/donate/info/for-us/title',
            'help/donate/info/for-them/title',
            'help/donate/info/300/for-us/options/1',
            'help/donate/info/300/for-us/options/2',
            'help/donate/info/300/for-us/options/3',
            'help/donate/info/300/for-them/options/1',
            'help/donate/info/500/for-us/options/1',
            'help/donate/info/500/for-us/options/2',
            'help/donate/info/500/for-us/options/3',
            'help/donate/info/500/for-them/options/1',
            'help/donate/info/1000/for-us/options/1',
            'help/donate/info/1000/for-us/options/2',
            'help/donate/info/1000/for-them/options/1',
            'help/donate/info/1000/for-them/options/2',
            'help/donate/info/1000/for-them/options/3',
            'help/donate/formcomment',
            'help/donate/short-dest',
            'help/donate/targets',
        ],
        'texts': [],
    })
}).then((i18n) => {
    const language = i18n.detectLanguage()

    const defaultProvider = language === LanguageType.RU ? ProvideType.YANDEX_MONEY : ProvideType.PAYPAL
    const defaultCurrency = CurrencyType[i18n.settings.language[language].defaultCurrency]

    // Init store for popup
    const popupInitialState = {
        modal: donateModalInitialState.modal,
        form: {
            ...donateModalInitialState.form,
            currencySettings: i18n.settings.currency,
        },
    }
    const popupStore = createStore(donateModalReducer, popupInitialState)
    ReactDOM.render(
        h(Provider, {store: popupStore},
            h(Popup(i18n))
        ),
        document.querySelector('#react-donate-popup-entry')
    )

    Array.prototype.slice.apply(document.querySelectorAll('.packages .package')).forEach((form) => {
        form.addEventListener('submit', (e) => {
            e.preventDefault()
            popupStore.dispatch(setProvider(defaultProvider))
            popupStore.dispatch(setCurrency(defaultCurrency))
            popupStore.dispatch(setAmount(parseInt(form.querySelector('input[name=sum]').value, 10)))
            popupStore.dispatch(setTargets(form.querySelector('input[name=formcomment]').value))
            popupStore.dispatch(setFormComment(form.querySelector('input[name=short-dest]').value))
            popupStore.dispatch(setShortDesc(form.querySelector('input[name=targets]').value))
            popupStore.dispatch(setModalDisplayed(true))
        })
    })
}).catch((e) => {
    console.error(e.stack)
})

/*
 Left menu bar
  */
const STICKY_MARGIN = 5
document.addEventListener('DOMContentLoaded', () => {
    Array.prototype.slice.apply(document.querySelectorAll('.category-menu')).forEach((menu) => {
        // Highlight current item
        const highlightItems = () => {
            Array.prototype.slice.apply(menu.querySelectorAll('.category-menu_item')).forEach((item) => {
                const url = new URL(item.getAttribute('href'), window.location)
                if (url.href === location.href) {
                    item.classList.add('category-menu_item--active')
                }
                else {
                    item.classList.remove('category-menu_item--active')
                }
            })
        }
        window.addEventListener('hashchange', highlightItems, false)
        highlightItems()

        // Make sticky menu
        const menuBody = menu.querySelector('.category-menu_body')
        const footerEl = document.querySelector('footer')
        const bodyEl = document.body
        const htmlEl = document.documentElement

        const bodyBounds = bodyEl.getBoundingClientRect()
        const menuBounds = menu.getBoundingClientRect()
        const footerBounds = footerEl.getBoundingClientRect()
        const menuBodyBounds = menuBody.getBoundingClientRect()

        const availableHeight = bodyBounds.height - footerBounds.height
        const menuPosition = menuBounds.top - bodyBounds.top
        const maxDif = availableHeight - menuBodyBounds.height - menuPosition - STICKY_MARGIN

        const checkSticky = () => {
            const bodyScroll = window.pageYOffset
                || htmlEl.scrollTop
                || bodyEl.scrollTop || 0

            const dif = Math.min(Math.max(bodyScroll - menuPosition + STICKY_MARGIN, 0), maxDif)

            menuBody.style.top = `${dif}px`
        }
        document.addEventListener('scroll', checkSticky)
        checkSticky()
    })
})

<|endoftext|>