<commit_before>angular.module('HNSearch.controllers', ['ngSanitize', 'ngDropdowns', 'pasvaz.bindonce'])

.run(['settings', function(settings) {
  $('body').attr('rel', settings.get().style);
}])

.controller('SearchCtrl', ['$scope', '$location', '$http', '$stateParams', '$sce', 'search', 'settings', 'hot', 'starred', 'Analytics', function($scope, $location, $http, $stateParams, $sce, search, settings, hot, starred, Analytics) {
  // Init search et params
  $scope.query = search.query;
  $scope.state = '';
  $scope.settings = settings.get();
  $scope.results = null;
  $scope.story = {};
  $scope.placeholder = '';

  var getIndex = function(q) {
    if ($scope.settings.sort === 'byDate') {
      return settings.indexSortedByDate;
    } else if (q.length <= 2) {
      return settings.indexSortedByPopularityOrdered;
    } else {
      return settings.indexSortedByPopularity;
    }
  };

  var parseQuery = function(query, params) {
    params.tagFilters = params.tagFilters || [];
    params.numericFilters = params.numericFilters || [];

    // authors:pg (ORed)
    var authors = [];
    while (true) {
      var matches = query.match(/(author|by):([^ ]+)/);
      if (!matches) {
        break;
      }
      if (matches.length > 0) {
        authors.push(matches[2]);
        query = query.replace(matches[1] + ':' + matches[2], '');
      }
    }
    if (authors.length > 0) {
      var tags = [];
      for (var i = 0; i < authors.length; ++i) {
        tags.push('author_' + authors[i]);
      }
      params.tagFilters.push(tags);
    }

    // points>42 (ANDed)
    while (true) {
      var matches = query.match(/points(=|:|<|>|<=|>=)([0-9]+)/);
      if (!matches) {
        break;
      }
      if (matches.length > 0) {
        params.numericFilters.push('points' + matches[1] + matches[2]);
        query = query.replace('points' + matches[1] + matches[2], '');
      }
    }

    // date>1395440948 (ANDed)
    while (true) {
      var matches = query.match(/date(=|:|<|>|<=|>=)([0-9]+)/);
      if (!matches) {
        break;
      }
      if (matches.length > 0) {
        params.numericFilters.push('created_at_i' + matches[1] + matches[2]);
        query = query.replace('date' + matches[1] + matches[2], '');
      }
    }

    // story:ID (ORed)
    var stories = [];
    while (true) {
      var matches = query.match('story:([0-9]+)');
      if (!matches) {
        break;
      }
      if (matches.length > 0) {
        stories.push(matches[1]);
        query = query.replace('story:' + matches[1], '');
      }
    }
    if (stories.length > 0) {
      var tags = [];
      for (var i = 0; i < stories.length; ++i) {
        tags.push('story_' + stories[i]);
      }
      params.tagFilters.push(tags);
    }

    return { query: query, params: params };
  };

  //Search scope
  $scope.getSearch = function(noProgres) {
    if (!noProgres) {
      NProgress.start();
    }
    var _search = function(ids) {
      var parsedQuery = parseQuery(search.query, search.getParams(ids));
      getIndex(parsedQuery.query).search(parsedQuery.query, undefined, parsedQuery.params).then(function(results) {
        if (parsedQuery.query === results.query) {
          $scope.results = results;
        }
        if (!noProgres) {
          NProgress.done();
        }
      });
    };
    $scope.query = search.query;

    if ($scope.state === 'hot') {
      $scope.results = null;
      hot.get().then(function(ids) {
        _search(ids);
      });
    } else if ($scope.state === 'starred') {
      _search(starred.all());
    } else if (search.storyID) {
      $scope.loadComments(search.storyID);
      _search([ search.storyID ]);
      search.storyID = null;
    } else {
      _search();
    }
  };

  $scope.loadComments = function(id, $event) {
    if ($event) {
      $event.preventDefault();
    }

    $('.item-show-comments').removeClass('item-show-comments');

    // reset previous comments
    var s = $scope.story[id];
    $scope.story = {};
    if (s) {
      return;
    }

    if ($scope.results) {
      var found = false;
      for (var i = 0; i < $scope.results.hits.length; ++i) {
        if ($scope.results.hits[i].objectID == id) {
          found = true;
          break;
        }
      }
      if (!found) {
        return;
      }
    }

    NProgress.start();
    $http.get($location.protocol() + '://hn.algolia.com/api/v1/items/' + id).success(function(data) {
      NProgress.done();

      $scope.story[id] = { comments: data };

      var item = $event ? $($event.currentTarget).closest('.item') : $('.item_' + id);
      item.addClass('item-show-comments');
      $(window).scrollTop(item.offset().top - $('.page-header').outerHeight() - $('.main > header').outerHeight());
    });
  };

  $scope.sortBy = function(order) {
    $scope.settings.page = 0;
    $scope.settings.sort = order;
  };

  $scope.selectDate = function(date) {
    $scope.settings.dateRange = date;
  };

  $scope.pageTitle = function() {
    switch ($scope.state) {
    case undefined: case '': return $scope.settings.style === 'default' ? '' : 'All';
    case "ask-hn": return "Ask HN";
    case "show-hn": return "Show HN";
    case "jobs": return "Jobs";
    case "polls": return "Polls";
    case "hot": return "Hot";
    case "starred": return "Starred";
    case "user": return $scope.settings.login;
    default: return "HN Search";
    }
  }

  $scope.toggleStar = function($event, id) {
    $event.preventDefault();
    starred.toggle(id);
    // stupid animation
    var target = $('.sidebar .icon-star');
    var elementToDrag = $($event.currentTarget).not('.starred').find('.icon-star').eq(0);
    if ( elementToDrag.length != 0 ) {
      var clone = elementToDrag
        .clone()
        .offset({
          top: elementToDrag.offset().top,
          left: elementToDrag.offset().left
        })
        .css({
          'opacity': '0.8',
          'position': 'absolute',
          'z-index': '100',
          'color': '#FF742B'
        })
        .appendTo($('body'))
        .animate({
          'top': target.offset().top + 0,
          'left': target.offset().left + 0,
          'width': 75,
          'height': 75
        }, 700, 'linear');

      clone.animate({
        'width': 0,
        'height': 0
      }, function () {
        $(this).detach();
      });
    }
  };

  $scope.isStarred = function(id) {
    return starred.is(id);
  };

  //Dropdowns
  //https://github.com/jseppi/angular-dropdowns
  $scope.ddSelectType = [
    {
      text: 'All',
      value: 'all',
    }, {
      text: 'Stories',
      value: 'story'
    }, {
      text: 'Comments',
      value: 'comment'
    }
  ];
  $scope.ddTypeSelected = angular.copy($scope.ddSelectType[0]);
  for (var i = 0; i < $scope.ddSelectType.length; ++i) {
    if ($scope.ddSelectType[i].value === $scope.settings.type) {
      $scope.ddTypeSelected = angular.copy($scope.ddSelectType[i]);
    }
  }

  $scope.ddSelectSort = [
    {
      text: 'Popularity',
      value: 'byPopularity',
    }, {
      text: 'Date',
      value: 'byDate'
    }
  ];
  $scope.ddSortSelected = angular.copy($scope.ddSelectSort[0]);
  for (var i = 0; i < $scope.ddSelectSort.length; ++i) {
    if ($scope.ddSelectSort[i].value === $scope.settings.sort) {
      $scope.ddSortSelected = angular.copy($scope.ddSelectSort[i]);
    }
  }

  $scope.ddSelectDate = [
    {
      text: 'All time',
      value: 'all'
    },
    {
      text: 'Last 24h',
      value: 'last24h',
    }, {
      text: 'Past Week',
      value: 'pastWeek'
    }, {
      text: 'Past Month',
      value: 'pastMonth'
    }, {
      text: 'Custom range',
      value: 'custom'
    }
  ];
  $scope.ddDateSelected = angular.copy($scope.ddSelectDate[0]);
  for (var i = 0; i < $scope.ddSelectDate.length; ++i) {
    if ($scope.ddSelectDate[i].value === $scope.settings.dateRange) {
      $scope.ddDateSelected = angular.copy($scope.ddSelectDate[i]);
    }
  }

  $scope.selectType = function(selected) {
    $scope.settings.type = selected.value;
  };

  $scope.selectInput = function($event) {
    $event.preventDefault();
    $('.page-header input[type="search"]').select();
  };

  $scope.widerDateRange = function($event) {
    $event.preventDefault();
    $scope.settings.dateRange = 'all';
  };

  $scope.searchAllItems = function($event) {
    $event.preventDefault();
    $scope.settings.type = 'all';
    $scope.ddTypeSelected = angular.copy($scope.ddSelectType[0]);
  };

  $scope.ddMenuShare = [
    {
      text: 'Share on Twitter',
      icon: 'icon-twitter',
      share: 'twitter'
    }, {
      text: 'Share on Facebook',
      icon: 'icon-facebook',
      share: 'facebook'
    }, {
      text: 'Share by Email',
      icon: 'icon-envelope-o',
      share: 'email'
    }
  ];



  // Share item
  $scope.shareItem = function(selected, hit) {
    var url = hit ? $location.protocol() + '://' + $location.host() + "/story/" + hit.objectID + "/" + $scope.friendly(hit.title) : window.location.href;
    var title = (hit ? hit.title + ' - ' : ($scope.query ? 'I just searched for "' + $scope.query + '" on Hacker News - ' : '')) + 'Hacker News Search';
    switch (selected.share){
      case 'twitter':
        window.open("https://twitter.com/share?url=" + escape(url) + "&text=" + title, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=300,width=600');
        break;
      case 'facebook':
        window.open("https://www.facebook.com/sharer/sharer.php?u=" + escape(url) + "&t=" + title, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=300,width=600');
        break;
      case 'email':
        window.location.href = "mailto:?subject=" + title + "&body=" + url;
        break;
    }
  };

  // Pagination
  $scope.nextPage = function() {
    $scope.toPage($scope.settings.page + 1);
  };
  $scope.prevPage = function() {
    if ($scope.settings.page > 0) {
      $scope.toPage($scope.settings.page - 1);
    }
  };
  $scope.toPage = function(page) {
    $scope.settings.page = page;
  };
  $scope.getPages = function(results) {
    var pages = [];
    var min;
    if ($scope.settings.page > 5) {
      pages.push(0);
      pages.push('...');
      min = 0;
    } else {
      for (var i = 0; i < $scope.settings.page + 5 && i < results.nbPages; ++i) {
        pages.push(i);
        min = i;
      }
    }
    for (var i = $scope.settings.page - 5; i < $scope.settings.page + 5; ++i) {
      if (i >= 0 && i < results.nbPages && i > min && i < results.nbPages) {
        pages.push(i);
      }
    }
    if ($scope.settings.page < results.nbPages - 5) {
      pages.push('...');
      pages.push(results.nbPages - 1);
    }
    return pages;
  };

  $scope.gotoMenu = function($event, path) {
    $event.preventDefault();
    $scope.story = {};
    $location.path(path).search($location.search());
    window.scrollTo(0, 0);
  };

  $scope.friendly = function(v) {
    return v && $.friendly_id(v);
  }

  $scope.getURL = function() {
    return location.href;
  };

  // Watch settings
  $scope.$watchCollection('settings', function(newSettings, oldSettings) {
    if (newSettings.page == oldSettings.page) {
      $scope.settings.page = 0;
    }

    if (newSettings.type === 'all') {
      $scope.placeholder = 'Stories, polls, jobs, comments';
    } else if (newSettings.type === 'story') {
      $scope.placeholder = 'Search stories by title, url or author';
    } else if (newSettings.type === 'comment') {
      $scope.placeholder = 'Search comments';
    }

    window.scrollTo(0, 0);
    search.applySettings(newSettings, $scope.state);
    $scope.getSearch();
    Analytics.trackPage('/' + location.href.split('/').slice(3).join('/'));
  });

  // Watch query
  $scope.$watch('query', function (newValue, oldValue) {
    if(newValue === oldValue || typeof newValue === 'undefined') {
      return;
    }
    $scope.settings.page = 0;
    search.query = newValue;
    $scope.getSearch(true);
  });
  $scope.reset = function() {
    search.query = $scope.query = '';
    settings.reset();
  };

  // Watch+Handle page change
  //  -> if on "starred", backup the settings & use byDate/all/<empty>
  $scope.savedSettings = null;
  $scope.savedQuery = null;
  var first = true;
  $scope.$watch('state', function() {
    if ($scope.state === 'starred') {
      if (!$scope.savedSettings) {<commit_msg>DRY + ensure the right options are selected<commit_after>angular.module('HNSearch.controllers', ['ngSanitize', 'ngDropdowns', 'pasvaz.bindonce'])

.run(['settings', function(settings) {
  $('body').attr('rel', settings.get().style);
}])

.controller('SearchCtrl', ['$scope', '$location', '$http', '$stateParams', '$sce', 'search', 'settings', 'hot', 'starred', 'Analytics', function($scope, $location, $http, $stateParams, $sce, search, settings, hot, starred, Analytics) {
  // Init search et params
  $scope.query = search.query;
  $scope.state = '';
  $scope.settings = settings.get();
  $scope.results = null;
  $scope.story = {};
  $scope.placeholder = '';

  var getIndex = function(q) {
    if ($scope.settings.sort === 'byDate') {
      return settings.indexSortedByDate;
    } else if (q.length <= 2) {
      return settings.indexSortedByPopularityOrdered;
    } else {
      return settings.indexSortedByPopularity;
    }
  };

  var parseQuery = function(query, params) {
    params.tagFilters = params.tagFilters || [];
    params.numericFilters = params.numericFilters || [];

    // authors:pg (ORed)
    var authors = [];
    while (true) {
      var matches = query.match(/(author|by):([^ ]+)/);
      if (!matches) {
        break;
      }
      if (matches.length > 0) {
        authors.push(matches[2]);
        query = query.replace(matches[1] + ':' + matches[2], '');
      }
    }
    if (authors.length > 0) {
      var tags = [];
      for (var i = 0; i < authors.length; ++i) {
        tags.push('author_' + authors[i]);
      }
      params.tagFilters.push(tags);
    }

    // points>42 (ANDed)
    while (true) {
      var matches = query.match(/points(=|:|<|>|<=|>=)([0-9]+)/);
      if (!matches) {
        break;
      }
      if (matches.length > 0) {
        params.numericFilters.push('points' + matches[1] + matches[2]);
        query = query.replace('points' + matches[1] + matches[2], '');
      }
    }

    // date>1395440948 (ANDed)
    while (true) {
      var matches = query.match(/date(=|:|<|>|<=|>=)([0-9]+)/);
      if (!matches) {
        break;
      }
      if (matches.length > 0) {
        params.numericFilters.push('created_at_i' + matches[1] + matches[2]);
        query = query.replace('date' + matches[1] + matches[2], '');
      }
    }

    // story:ID (ORed)
    var stories = [];
    while (true) {
      var matches = query.match('story:([0-9]+)');
      if (!matches) {
        break;
      }
      if (matches.length > 0) {
        stories.push(matches[1]);
        query = query.replace('story:' + matches[1], '');
      }
    }
    if (stories.length > 0) {
      var tags = [];
      for (var i = 0; i < stories.length; ++i) {
        tags.push('story_' + stories[i]);
      }
      params.tagFilters.push(tags);
    }

    return { query: query, params: params };
  };

  //Search scope
  $scope.getSearch = function(noProgres) {
    if (!noProgres) {
      NProgress.start();
    }
    var _search = function(ids) {
      var parsedQuery = parseQuery(search.query, search.getParams(ids));
      getIndex(parsedQuery.query).search(parsedQuery.query, undefined, parsedQuery.params).then(function(results) {
        if (parsedQuery.query === results.query) {
          $scope.results = results;
        }
        if (!noProgres) {
          NProgress.done();
        }
      });
    };
    $scope.query = search.query;

    if ($scope.state === 'hot') {
      $scope.results = null;
      hot.get().then(function(ids) {
        _search(ids);
      });
    } else if ($scope.state === 'starred') {
      _search(starred.all());
    } else if (search.storyID) {
      $scope.loadComments(search.storyID);
      _search([ search.storyID ]);
      search.storyID = null;
    } else {
      _search();
    }
  };

  $scope.loadComments = function(id, $event) {
    if ($event) {
      $event.preventDefault();
    }

    $('.item-show-comments').removeClass('item-show-comments');

    // reset previous comments
    var s = $scope.story[id];
    $scope.story = {};
    if (s) {
      return;
    }

    if ($scope.results) {
      var found = false;
      for (var i = 0; i < $scope.results.hits.length; ++i) {
        if ($scope.results.hits[i].objectID == id) {
          found = true;
          break;
        }
      }
      if (!found) {
        return;
      }
    }

    NProgress.start();
    $http.get($location.protocol() + '://hn.algolia.com/api/v1/items/' + id).success(function(data) {
      NProgress.done();

      $scope.story[id] = { comments: data };

      var item = $event ? $($event.currentTarget).closest('.item') : $('.item_' + id);
      item.addClass('item-show-comments');
      $(window).scrollTop(item.offset().top - $('.page-header').outerHeight() - $('.main > header').outerHeight());
    });
  };

  $scope.sortBy = function(order) {
    $scope.settings.page = 0;
    $scope.settings.sort = order;
  };

  $scope.selectDate = function(date) {
    $scope.settings.dateRange = date;
  };

  $scope.pageTitle = function() {
    switch ($scope.state) {
    case undefined: case '': return $scope.settings.style === 'default' ? '' : 'All';
    case "ask-hn": return "Ask HN";
    case "show-hn": return "Show HN";
    case "jobs": return "Jobs";
    case "polls": return "Polls";
    case "hot": return "Hot";
    case "starred": return "Starred";
    case "user": return $scope.settings.login;
    default: return "HN Search";
    }
  }

  $scope.toggleStar = function($event, id) {
    $event.preventDefault();
    starred.toggle(id);
    // stupid animation
    var target = $('.sidebar .icon-star');
    var elementToDrag = $($event.currentTarget).not('.starred').find('.icon-star').eq(0);
    if ( elementToDrag.length != 0 ) {
      var clone = elementToDrag
        .clone()
        .offset({
          top: elementToDrag.offset().top,
          left: elementToDrag.offset().left
        })
        .css({
          'opacity': '0.8',
          'position': 'absolute',
          'z-index': '100',
          'color': '#FF742B'
        })
        .appendTo($('body'))
        .animate({
          'top': target.offset().top + 0,
          'left': target.offset().left + 0,
          'width': 75,
          'height': 75
        }, 700, 'linear');

      clone.animate({
        'width': 0,
        'height': 0
      }, function () {
        $(this).detach();
      });
    }
  };

  $scope.isStarred = function(id) {
    return starred.is(id);
  };

  //Dropdowns
  //https://github.com/jseppi/angular-dropdowns
  var getSelectOption = function(options, selected) {
    for (var i = 0; i < options.length; ++i) {
      if (options[i].value === selected) {
        return angular.copy(options[i]);
      }
    }
    return null;
  };
  $scope.ddSelectType = [
    {
      text: 'All',
      value: 'all',
    }, {
      text: 'Stories',
      value: 'story'
    }, {
      text: 'Comments',
      value: 'comment'
    }
  ];
  $scope.ddSelectSort = [
    {
      text: 'Popularity',
      value: 'byPopularity',
    }, {
      text: 'Date',
      value: 'byDate'
    }
  ];
  $scope.ddSelectDate = [
    {
      text: 'All time',
      value: 'all'
    },
    {
      text: 'Last 24h',
      value: 'last24h',
    }, {
      text: 'Past Week',
      value: 'pastWeek'
    }, {
      text: 'Past Month',
      value: 'pastMonth'
    }, {
      text: 'Custom range',
      value: 'custom'
    }
  ];

  $scope.ddDateSelected = getSelectOption($scope.ddSelectDate, $scope.settings.dateRange) || getSelectOption($scope.ddSelectDate, 'all');
  $scope.ddSortSelected = getSelectOption($scope.ddSelectSort, $scope.settings.sort) || getSelectOption($scope.ddSelectSort, 'byPopularity');
  $scope.ddTypeSelected = getSelectOption($scope.ddSelectType, $scope.settings.type) || getSelectOption($scope.ddSelectType, 'all');

  $scope.selectType = function(selected) {
    $scope.settings.type = selected.value;
  };

  $scope.selectInput = function($event) {
    $event.preventDefault();
    $('.page-header input[type="search"]').select();
  };

  $scope.widerDateRange = function($event) {
    $event.preventDefault();
    $scope.settings.dateRange = 'all';
  };

  $scope.searchAllItems = function($event) {
    $event.preventDefault();
    $scope.settings.type = 'all';
    $scope.ddTypeSelected = angular.copy($scope.ddSelectType[0]);
  };

  // Share item
  $scope.ddMenuShare = [
    {
      text: 'Share on Twitter',
      icon: 'icon-twitter',
      share: 'twitter'
    }, {
      text: 'Share on Facebook',
      icon: 'icon-facebook',
      share: 'facebook'
    }, {
      text: 'Share by Email',
      icon: 'icon-envelope-o',
      share: 'email'
    }
  ];
  $scope.shareItem = function(selected, hit) {
    var url = hit ? $location.protocol() + '://' + $location.host() + "/story/" + hit.objectID + "/" + $scope.friendly(hit.title) : window.location.href;
    var title = (hit ? hit.title + ' - ' : ($scope.query ? 'I just searched for "' + $scope.query + '" on Hacker News - ' : '')) + 'Hacker News Search';
    switch (selected.share){
      case 'twitter':
        window.open("https://twitter.com/share?url=" + escape(url) + "&text=" + title, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=300,width=600');
        break;
      case 'facebook':
        window.open("https://www.facebook.com/sharer/sharer.php?u=" + escape(url) + "&t=" + title, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=300,width=600');
        break;
      case 'email':
        window.location.href = "mailto:?subject=" + title + "&body=" + url;
        break;
    }
  };

  // Pagination
  $scope.nextPage = function() {
    $scope.toPage($scope.settings.page + 1);
  };
  $scope.prevPage = function() {
    if ($scope.settings.page > 0) {
      $scope.toPage($scope.settings.page - 1);
    }
  };
  $scope.toPage = function(page) {
    $scope.settings.page = page;
  };
  $scope.getPages = function(results) {
    var pages = [];
    var min;
    if ($scope.settings.page > 5) {
      pages.push(0);
      pages.push('...');
      min = 0;
    } else {
      for (var i = 0; i < $scope.settings.page + 5 && i < results.nbPages; ++i) {
        pages.push(i);
        min = i;
      }
    }
    for (var i = $scope.settings.page - 5; i < $scope.settings.page + 5; ++i) {
      if (i >= 0 && i < results.nbPages && i > min && i < results.nbPages) {
        pages.push(i);
      }
    }
    if ($scope.settings.page < results.nbPages - 5) {
      pages.push('...');
      pages.push(results.nbPages - 1);
    }
    return pages;
  };

  $scope.gotoMenu = function($event, path) {
    $event.preventDefault();
    $scope.story = {};
    $location.path(path).search($location.search());
    window.scrollTo(0, 0);
  };

  $scope.friendly = function(v) {
    return v && $.friendly_id(v);
  }

  $scope.getURL = function() {
    return location.href;
  };

  // Watch settings
  $scope.$watchCollection('settings', function(newSettings, oldSettings) {
    if (newSettings.page == oldSettings.page) {
      $scope.settings.page = 0;
    }

    if (newSettings.type === 'all') {
      $scope.placeholder = 'Stories, polls, jobs, comments';
    } else if (newSettings.type === 'story') {
      $scope.placeholder = 'Search stories by title, url or author';
    } else if (newSettings.type === 'comment') {
      $scope.placeholder = 'Search comments';
    }

    $scope.ddDateSelected = getSelectOption($scope.ddSelectDate, newSettings.dateRange);
    $scope.ddSortSelected = getSelectOption($scope.ddSelectSort, newSettings.sort);
    $scope.ddTypeSelected = getSelectOption($scope.ddSelectType, newSettings.type);

    window.scrollTo(0, 0);
    search.applySettings(newSettings, $scope.state);
    $scope.getSearch();
    Analytics.trackPage('/' + location.href.split('/').slice(3).join('/'));
  });

  // Watch query
  $scope.$watch('query', function (newValue, oldValue) {
    if(newValue === oldValue || typeof newValue === 'undefined') {
      return;
    }
    $scope.settings.page = 0;
    search.query = newValue;
    $scope.getSearch(true);
  });
  $scope.reset = function() {
    search.query = $scope.query = '';
    settings.reset();
  };

  // Watch+Handle page change
  //  -> if on "starred", backup the settings & use byDate/all/<empty>
  $scope.savedSettings = null;
  $scope.savedQuery = null;
  var first = true;
  $scope.$watch('state', function() {
    if ($scope.state === 'starred') {
      if (!$scope.savedSettings) {
{'fraction_non_alphanumeric': 0.18678567101490245, 'fraction_numerical': 0.008440693025322079, 'mean_word_length': 2.4574141301312484, 'pattern_counts': {'":': 14, '<': 37, '<?xml version=': 0, '>': 41, 'https://': 6, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5091725', 'n_tokens_mistral': 8403, 'n_tokens_neox': 8179, 'n_words': 1554}