topic-list.directive.js 8.69 KB
(function() {
  'use strict';

  angular
    .module('dialoga')
    .directive('topicList', topicList);

  /** @ngInject */
  function topicList() {

    /** @ngInject */
    function TopicListController($scope, $element, $location, $filter, $log) {
      $log.debug('TopicListController');

      // alias
      var vm = this;

      // dependencies
      vm.$scope = $scope;
      vm.$element = $element;
      vm.$location = $location;
      vm.$filter = $filter;
      vm.$log = $log;
      vm.defaultLimit = 6;

      // initialization
      vm.init();
    }

    TopicListController.prototype.init = function() {
      var vm = this;

      if (!vm.article) {
        vm.$log.debug('no article to display. Tip: use a ng-if before use this directive');
        return;
      }

      vm.categories = vm.article.categories;
      vm.programs = vm.article.children;
      vm.orderCriteries = [
        { label: 'Título', name: 'titulo' },
        { label: 'Tema', name: 'tema' },
        { label: 'Aleatório', name: 'aleatorio' }
      ];

      vm.filtredProgramList = vm.getFiltredPrograms();
      vm.search = vm.$location.search();

      // Add initial values for the filter
      vm.query = (vm.search && vm.search.filtro) ? vm.search.filtro : null;
      vm.limitTo = (vm.search && vm.search.limite) ? parseInt(vm.search.limite, 10) : vm.defaultLimit;
      vm.categoryFilter = (vm.search && vm.search.tema) ? vm.getCategoryBySlug(vm.search.tema) : null;
      vm.orderCriteria = (vm.search && vm.search.ordem) ? { name: vm.search.ordem } : null;
      vm.reverse = (vm.search && vm.search.reverso) ? true : false;

      if (!angular.equals({}, vm.search)) {
        var $el = vm.$element;
        angular.element('body').animate({scrollTop: $el.offset().top}, 'slow');
      }

      // update window location params
      vm.$scope.$watch('vm.query', function(newValue/*, oldValue*/) {
        vm.search.filtro = newValue ? newValue : null;
        vm.$location.search('filtro', vm.search.filtro);
        if(vm.search.filtro){
          vm.limitTo = vm.programs.length;
        }else{
          vm.limitTo = vm.defaultLimit;
        }
        vm.filtredProgramList = vm.getFiltredPrograms();
      });

      vm.$scope.$watch('vm.limitTo', function(newValue/*, oldValue*/) {
        vm.search.limite = (newValue && newValue !== vm.defaultLimit)  ? newValue : null;
        vm.$location.search('limite', vm.search.limite);
        vm.filtredProgramList = vm.getFiltredPrograms();
      });

      vm.$scope.$watch('vm.categoryFilter', function(newValue/*, oldValue*/) {
        vm.search.tema = newValue ? newValue.slug : null;
        vm.$location.search('tema', vm.search.tema);
        if(vm.search.tema){
          vm.limitTo = vm.programs.length;
        }
        vm.filtredProgramList = vm.getFiltredPrograms();
      });

      vm.$scope.$watch('vm.orderCriteria', function(newValue/*, oldValue*/) {
        vm.search.ordem = (newValue && newValue.name) ? newValue.name : null;
        vm.$location.search('ordem', vm.search.ordem);
        vm.filtredProgramList = vm.getFiltredPrograms();
      });

      vm.$scope.$watch('vm.reverse', function(newValue/*, oldValue*/) {
        vm.search.reverso = newValue ? newValue : null;
        vm.$location.search('reverso', vm.search.reverso);
        vm.filtredProgramList = vm.getFiltredPrograms();
      });

    };

    TopicListController.prototype.resetFilterValues = function() {
      var vm = this;

      vm.query = null;
      vm.limitTo = vm.defaultLimit;
      vm.categoryFilter = null;
      vm.orderCriteria = null;
    };

    TopicListController.prototype.getIconClasses = function(category) {
      var vm = this;

      vm.$log.debug('[TODO] getIconClasses of category:', category);
      return 'glyphicon glyphicon-exclamation-sign';
    };

    TopicListController.prototype.getCategoryBySlug = function(categorySlug) {
      var vm = this;
      var result = null;

      angular.forEach(vm.categories, function(value/*, key*/) {
        if (value.slug === categorySlug) {
          result = value;
        }
      });

      return result;
    };

    TopicListController.prototype.filterByCategory = function(category, $event) {
      var vm = this;

      $event.stopPropagation();

      if (category !== vm.categoryFilter) {

        // selected new filter
        vm.categoryFilter = category;
      } else {
        vm.categoryFilter = null;
      }
    };

    TopicListController.prototype.showAll = function($event) {
      var vm = this;

      $event.stopPropagation();

      vm.resetFilterValues();
      vm.limitTo = vm.programs.length;
    };

    TopicListController.prototype.getFiltredPrograms = function() {
      var vm = this;

      var input = vm.programs;
      var output = input;
      var query = vm.query;
      var categoryFilter = vm.categoryFilter;
      var orderCriteria = vm.orderCriteria ? vm.orderCriteria : { name : 'aleatorio'};
      var filter = vm.$filter('filter');
      var orderBy = vm.$filter('orderBy');
      var limitTo = vm.$filter('limitTo');
      var limit = vm.limitTo ? vm.limitTo : 4;

      if (categoryFilter) {
        output = _filterByCategory(output, categoryFilter);
      }

      if (query) {
        output = filter(output, query, false);
      }

      switch (orderCriteria.name) {
        case 'titulo':
          output = orderBy(output, 'title', vm.reverse);
          break;
        case 'tema':
          output = orderBy(output, 'categories[0].name', vm.reverse);
          break;
        case 'more_participants':
          vm.$log.info('Criteria not handled yet: ', orderCriteria);
          break;
        case 'aleatorio':
          // shuffling
          // if (!vm._isShuffled){
          output = vm.filterShuffle(output);
          //   vm._isShuffled = true;
          // }

          if (vm.reverse) {
            output = output.slice().reverse();
          }

          break;
        default:
          vm.$log.warn('Criteria not matched: ', orderCriteria);
          break;
      }

      output = limitTo(output, limit);

      return output;
    };

    TopicListController.prototype.filterShuffle = function(input) {
      var result = [];
      var resultByCategory = {};

      // divide by categories
      for (var i = 0; i < input.length; i++) {
        var program = input[i];
        var categorySlug = program.categories[0].slug;

        if (!resultByCategory[categorySlug]) {
          resultByCategory[categorySlug] = [];
        }

        resultByCategory[categorySlug].push(program);
      }

      // shuffle each array
      var prop = null;
      var categoryWithPrograms = null;
      for (prop in resultByCategory) {
        if (resultByCategory.hasOwnProperty(prop)) {
          categoryWithPrograms = resultByCategory[prop];
          resultByCategory[prop] = shuffle(categoryWithPrograms);
        }
      }

      // Concat all into result array
      // > while has program at Lists on resultByCategory
      var hasProgram = true;
      while (hasProgram) {

        var foundProgram = false;
        // each categoryList with array of program
        prop = null;
        categoryWithPrograms = null;
        for (prop in resultByCategory) {

          if (resultByCategory.hasOwnProperty(prop)) {
            categoryWithPrograms = resultByCategory[prop];

            if (categoryWithPrograms.length > 0) {
              var pivotProgram = categoryWithPrograms.pop();
              result.push(pivotProgram);
              foundProgram = true;
            }
          }
        }

        if (!foundProgram) {
          hasProgram = false;
        }
      }

      return result;
    };

    var directive = {
      restrict: 'E',
      templateUrl: 'app/components/programas/programas.html',
      scope: {
        article: '='
      },
      controller: TopicListController,
      controllerAs: 'vm',
      bindToController: true
    };

    return directive;
  }

  function _filterByCategory (input, category) {
    input = input || [];

    if (!category) {
      // no filter
      return input;
    }

    var out = [];
    for (var i = 0; i < input.length; i++) {
      var program = input[i];
      if (program.categories[0].slug === category.slug) {
        out.push(program);
      }
    }

    return out;
  }

  // -> Fisher–Yates shuffle algorithm
  function shuffle (array) {
    var currentIndex = array.length, temporaryValue, randomIndex ;

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

      // Pick a remaining element...
      randomIndex = Math.floor(Math.random() * currentIndex);
      currentIndex -= 1;

      // And swap it with the current element.
      temporaryValue = array[currentIndex];
      array[currentIndex] = array[randomIndex];
      array[randomIndex] = temporaryValue;
    }

    return array;
  }

})();