<commit_before>angular.module('BootstrapAddons')
.directive('timeslider', function($document, $timeout) {
  const SVG_ID = "timesliderSvg";
  const CONTROLS_WIDTH = 72; //fixed width of buttons used to advance timeslider
  return {
    restrict: 'E',
    scope: {
      end: "=",
      onClear: "&",
      onChange: "&",
      start: "=",
      ticks: "@",
      width: "@",
    },
    templateUrl: 'timeslider/timeslider.html',
    replace: true,
    link: function(scope, elem, attr) {
      var brush;
      var autoScale = false;
      if(!scope.width) {
        autoScale = true;
      }
      scope.actionIcon = "glyphicon-play";
      var intervalId = null;
      drawTimeline();

      scope.$watch('end', function(newVal, oldVal) {
        if(newVal.getTime() !== oldVal.getTime()) {
          scope.end = newVal;
          redraw();
        }
      }, true);

      scope.$on('timesliderForceRender', function() {
        redraw();
      });

      scope.togglePlay = function() {
        if(intervalId) {
          pause();
        } else {
          play();
        }
      }
      scope.stepBack = function() {
        var nextStart = new Date(brush.extent()[0].getTime() - getBrushSize());
        var nextStop = brush.extent()[0];
        if (nextStop.getTime() <= scope.start.getTime()) {
          nextStart = new Date(scope.end.getTime() - getBrushSize());
          nextStop = scope.end;
        }
        select(nextStart, nextStop);
      }
      scope.stepForward = function() {
        var nextStart = brush.extent()[1];
        var nextStop = new Date(brush.extent()[1].getTime() + getBrushSize());
        if (nextStart.getTime() >= scope.end.getTime()) {
          nextStart = scope.start;
          nextStop = new Date(scope.start.getTime() + getBrushSize());
        }
        select(nextStart, nextStop);
      }

      function brushend() {
        //Brush events fired by interactions directly on svg are outside of angularjs
        //Wrap callbacks in $timeout so callbacks are always fireed within Angular's $apply context
        if(brush.extent()[0].getTime() === brush.extent()[1].getTime()) {
          $timeout(function() {
            scope.onClear()();
          });
        } else {
          $timeout(function() {
            scope.onChange()(brush.extent()[0], brush.extent()[1]);
          });
        }
      }

      function select(start, end) {
        //update extent
        brush.extent([start, end]);
        //draw brush to match new extent
        brush(d3.select('.brush'));
        //fire brush events
        brush.event(d3.select('.brush'));
      }

      function pause() {
        scope.actionIcon = "glyphicon-play";
        if(intervalId) {
          clearInterval(intervalId);
          intervalId = null;
        }
      }

      function play() {
        scope.actionIcon = "glyphicon-pause";
        intervalId = setInterval(
          function() {
            scope.stepForward();
          },
          1000
        );
      }

      function getBrushSize() {
        var brushSize = brush.extent()[1].getTime() - brush.extent()[0].getTime();
        if (brushSize <= 0) {
          brushSize = (scope.end.getTime() - scope.start.getTime()) / 45;
        }
        return brushSize;
      }

      function redraw() {
        var oldBrush = brush.extent();
        drawTimeline();
        if(oldBrush[0].getTime() !== oldBrush[1].getTime()) {
          brush.extent([oldBrush[0], oldBrush[1]]);
          brush(d3.select('.brush'));
        }
      }

      function drawTimeline() {
        if(autoScale) {
          scope.width = elem[0].clientWidth - CONTROLS_WIDTH;
        }
        if(scope.width <= 0) {
          console.log("Element does not have enough width to support timeslider, unable to draw");
          return;
        }

        var container = d3.select("#timesliderContainer");
        container.selectAll('#' + SVG_ID).remove();
        var svg = container.append('svg')
          .attr("id", SVG_ID)
          .attr("width", scope.width)
          .attr("height", 22);
        svg.append('g').append('rect')
          .attr("x", 0)
          .attr("y", 0)<commit_msg>set min width if width is zero<commit_after>angular.module('BootstrapAddons')
.directive('timeslider', function($document, $timeout) {
  const SVG_ID = "timesliderSvg";
  const CONTROLS_WIDTH = 72; //fixed width of buttons used to advance timeslider
  return {
    restrict: 'E',
    scope: {
      end: "=",
      onClear: "&",
      onChange: "&",
      start: "=",
      ticks: "@",
      width: "@",
    },
    templateUrl: 'timeslider/timeslider.html',
    replace: true,
    link: function(scope, elem, attr) {
      var brush;
      var autoScale = false;
      if(!scope.width) {
        autoScale = true;
      }
      scope.actionIcon = "glyphicon-play";
      var intervalId = null;
      drawTimeline();

      scope.$watch('end', function(newVal, oldVal) {
        if(newVal.getTime() !== oldVal.getTime()) {
          scope.end = newVal;
          redraw();
        }
      }, true);

      scope.$on('timesliderForceRender', function() {
        redraw();
      });

      scope.togglePlay = function() {
        if(intervalId) {
          pause();
        } else {
          play();
        }
      }
      scope.stepBack = function() {
        var nextStart = new Date(brush.extent()[0].getTime() - getBrushSize());
        var nextStop = brush.extent()[0];
        if (nextStop.getTime() <= scope.start.getTime()) {
          nextStart = new Date(scope.end.getTime() - getBrushSize());
          nextStop = scope.end;
        }
        select(nextStart, nextStop);
      }
      scope.stepForward = function() {
        var nextStart = brush.extent()[1];
        var nextStop = new Date(brush.extent()[1].getTime() + getBrushSize());
        if (nextStart.getTime() >= scope.end.getTime()) {
          nextStart = scope.start;
          nextStop = new Date(scope.start.getTime() + getBrushSize());
        }
        select(nextStart, nextStop);
      }

      function brushend() {
        //Brush events fired by interactions directly on svg are outside of angularjs
        //Wrap callbacks in $timeout so callbacks are always fireed within Angular's $apply context
        if(brush.extent()[0].getTime() === brush.extent()[1].getTime()) {
          $timeout(function() {
            scope.onClear()();
          });
        } else {
          $timeout(function() {
            scope.onChange()(brush.extent()[0], brush.extent()[1]);
          });
        }
      }

      function select(start, end) {
        //update extent
        brush.extent([start, end]);
        //draw brush to match new extent
        brush(d3.select('.brush'));
        //fire brush events
        brush.event(d3.select('.brush'));
      }

      function pause() {
        scope.actionIcon = "glyphicon-play";
        if(intervalId) {
          clearInterval(intervalId);
          intervalId = null;
        }
      }

      function play() {
        scope.actionIcon = "glyphicon-pause";
        intervalId = setInterval(
          function() {
            scope.stepForward();
          },
          1000
        );
      }

      function getBrushSize() {
        var brushSize = brush.extent()[1].getTime() - brush.extent()[0].getTime();
        if (brushSize <= 0) {
          brushSize = (scope.end.getTime() - scope.start.getTime()) / 45;
        }
        return brushSize;
      }

      function redraw() {
        var oldBrush = brush.extent();
        drawTimeline();
        if(oldBrush[0].getTime() !== oldBrush[1].getTime()) {
          brush.extent([oldBrush[0], oldBrush[1]]);
          brush(d3.select('.brush'));
        }
      }

      function drawTimeline() {
        if(autoScale) {
          scope.width = elem[0].clientWidth - CONTROLS_WIDTH;
        }
        if(scope.width <= 0) scope.width = CONTROLS_WIDTH * 2;

        var container = d3.select("#timesliderContainer");
        container.selectAll('#' + SVG_ID).remove();
        var svg = container.append('svg')
          .attr("id", SVG_ID)
          .attr("width", scope.width)
          .attr("height", 22);
        svg.append('g').append('rect')
          .attr("x", 0)
          .attr("y", 0)
{'fraction_non_alphanumeric': 0.15194174757281553, 'fraction_numerical': 0.008131067961165049, 'mean_word_length': 1.9151043509020163, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '103758', 'n_tokens_mistral': 2519, 'n_tokens_neox': 2417, 'n_words': 487}