Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
directives.js 14.12 KiB
/******************************************************************************
 * Vipra Application
 * Directives
 ******************************************************************************/
/* globals angular, Vipra, bootbox, $ */
(function() {

  "use strict";

  var app = angular.module('vipra.directives', [
    'ui.router'
  ]);

  app.directive('topicLink', [function() {
    return {
      scope: {
        topic: '=',
        badge: '@',
        menu: '@'
      },
      restrict: 'E',
      replace: true,
      transclude: true,
      templateUrl: 'html/directives/topic-link.html',
      link: function($scope) {
        $scope.showBadge = $scope.badge !== 'false';
        $scope.showMenu = $scope.menu !== 'false';
      }
    };
  }]);

  app.directive('wordLink', [function() {
    return {
      scope: {
        word: '=',
        menu: '@'
      },
      restrict: 'E',
      replace: true,
      transclude: true,
      templateUrl: 'html/directives/word-link.html',
      link: function($scope) {
        $scope.showBadge = $scope.badge !== 'false';
        $scope.showMenu = $scope.menu !== 'false';
      }
    };
  }]);

  app.directive('articleLink', ['ArticleFactory', function(ArticleFactory) {
    return {
      scope: {
        article: '=',
        excerpt: '@',
        badge: '@',
        menu: '@'
      },
      restrict: 'E',
      replace: true,
      transclude: true,
      templateUrl: 'html/directives/article-link.html',
      link: function($scope) {
        $scope.showExcerpt = $scope.excerpt !== 'false';
        $scope.showBadge = $scope.badge !== 'false';
        $scope.showMenu = $scope.menu !== 'false';
        $scope.toggleExcerpt = function() {
          if (!$scope.excerptShown) {
            if ($scope.excerpt) {
              $scope.excerptShown = true;
            } else {
              ArticleFactory.get({
                id: $scope.article.id,
                excerpt: true
              }, function(data) {
                $scope.excerpt = data.text;
                $scope.excerptShown = true;
              });
            }
          } else {
            $scope.excerptShown = false;
          }
        };
      }
    };
  }]);

  app.directive('entityLink', [function() {
    return {
      scope: {
        entity: '=',
        menu: '@'
      },
      restrict: 'E',
      replace: true,
      transclude: true,
      templateUrl: 'html/directives/entity-link.html',
      link: function($scope) {
        $scope.showMenu = $scope.menu !== 'false';
      }
    };
  }]);

  app.directive('pagination', [function() {
    return {
      restrict: 'E',
      replace: true,
      scope: {
        total: '=',
        page: '=',
        limit: '=',
        change: '&'
      },
      controller: 'PaginationController',
      templateUrl: 'html/directives/pagination.html'
    };
  }]);

  app.directive('highcharts', [function() {
    return {
      scope: {
        highcharts: '='
      },
      link: function($scope, $element) {
        $scope.$watch('highcharts', function() {
          $element.highcharts($scope.highcharts);
        });
      }
    };
  }]);

  app.directive('bsRadio', [function() {
    return {
      scope: {
        bsRadio: '=',
        ngModel: '='
      },
      restrict: 'A',
      link: function($scope, $elem) {
        var setActive = function() {
          $elem.parent().children().removeClass("active");
          $elem.addClass("active");
        };

        if ($scope.ngModel === $scope.bsRadio)
          setActive();

        $elem.click(function() {
          $scope.$apply(function() {
            $scope.ngModel = $scope.bsRadio;
            setActive();
          });
        });
      }
    };
  }]);

  app.directive('bsPopover', ['$templateCache', '$compile',
    function($templateCache, $compile) {
      return {
        restrict: 'A',
        link: function($scope, $elem, $attrs) {
          var content = $attrs.popoverHtml;
          if ($attrs.popoverTemplate) {
            var template = $templateCache.get($attrs.popoverTemplate);
            content = $compile(template)($scope);
          }
          $scope.label = $attrs.popoverLabel;
          $elem.popover({
            animation: ($attrs.popoverAnimation === 'true') || true,
            container: $attrs.popoverContainer || 'body',
            content: content,
            delay: parseInt($attrs.popoverDelay || 1000, 10),
            html: $attrs.popoverHtml || true,
            placement: $attrs.popoverPlacement || 'right',
            title: $attrs.popoverTitle,
            trigger: $attrs.popoverTrigger || 'hover'
          });
        }
      };
    }
  ]);

  app.directive('bsTab', [function() {
    return {
      link: function($scope, $elem, $attrs) {
        $elem.on('shown.bs.tab', function() {
          if ($attrs.shown) {
            $scope.$eval($attrs.shown);
          }
          var hc = $($elem.data('target')).find('[highcharts]');
          if(hc.length) {
            hc.highcharts().reflow();
          }
        });
      }
    };
  }]);

  app.directive('bsAlert', [function() {
    return {
      scope: {
        ngModel: '=',
        type: '@',
        dismissible: '@'
      },
      replace: true,
      restrict: 'E',
      link: function($scope) {
        var classes = ['alert'];
        $scope.dismissible = $scope.dismissible !== 'false';
        if ($scope.dismissible) {
          classes.push('alert-dismissible');
        }
        switch ($scope.type) {
          case 'success':
          case 'info':
          case 'warning':
            classes.push('alert-' + $scope.type);
            break;
          case 'danger':
            /* falls through */
          default:
            classes.push('alert-danger');
        }
        $scope.classes = classes.join(' ');
      },
      templateUrl: 'html/directives/alert.html'
    };
  }]);

  app.directive('bsDatetimepicker', [function() {
    return {
      scope: {
        ngModel: '='
      },
      link: function($scope, $elem) {
        $elem.datetimepicker({
          sideBySide: true,
          calendarWeeks: true,
          showTodayButton: true,
          showClear: true,
          toolbarPlacement: 'top',
          useCurrent: false
        });
        $elem.on('dp.change', function(e) {
          $scope.$apply(function() {
            $scope.ngModel = e.date.toDate();
          });
        });
      }
    };
  }]);

  app.directive('sequenceDropdown', [function() {
    return {
      scope: {
        ngModel: '=',
        sequences: '=',
        dropup: '@'
      },
      link: function($scope) {
        $scope.showDropup = $scope.dropup === 'true';

        $scope.$watch('sequences', function(newValue) {
          if (newValue) {
            for (var i = 0, s; i < $scope.sequences.length; i++) {
              s = $scope.sequences[i];
              s.label = Vipra.windowLabel(s.window.startDate, s.window.windowResolution);
            }
          }
        });
      },
      templateUrl: '/html/directives/sequence-dropdown.html'
    };
  }]);

  app.directive('windowDropdown', [function() {
    return {
      scope: {
        ngModel: '=',
        windows: '=',
        dropup: '@'
      },
      link: function($scope) {
        $scope.showDropup = $scope.dropup === 'true';

        $scope.$watch('windows', function(newValue) {
          if (newValue) {
            for (var i = 0, w; i < $scope.windows.length; i++) {
              w = $scope.windows[i];
              w.label = Vipra.windowLabel(w.startDate, w.windowResolution);
            }
          }
        });
      },
      templateUrl: '/html/directives/window-dropdown.html'
    };
  }]);

  app.directive('sortBy', [function() {
    return {
      restrict: 'A',
      scope: {
        ngModel: '=',
        sortBy: '@'
      },
      link: function($scope, $elem) {
        $elem.click(function() {
          $scope.$apply(function() {
            $scope.reverse = false;
            if ($scope.ngModel === $scope.sortBy) {
              $scope.ngModel = '-' + $scope.sortBy;
              $scope.reverse = true;
            } else {
              $scope.ngModel = $scope.sortBy;
              $scope.reverse = false;
            }
          });
        });

        $scope.showCaret = function() {
          return $scope.ngModel === $scope.sortBy || $scope.ngModel === '-' + $scope.sortBy;
        };

        $scope.$watch('ngModel', function() {
          if ($scope.ngModel === $scope.sortBy)
            $scope.reverse = false;
          else if ($scope.ngModel === '-' + $scope.sortBy)
            $scope.reverse = true;
        });
      },
      transclude: true,
      template: '<span ng-transclude></span> <i class="fa" ng-class="{\'fa-caret-down\':!reverse, \'fa-caret-up\':reverse}" ng-show="showCaret()" ng-cloak></i>'
    };
  }]);

  app.directive('topicMenu', ['TopicFactory', function(TopicFactory) {
    return {
      scope: {
        topic: '=',
        right: '@'
      },
      restrict: 'E',
      templateUrl: 'html/directives/topic-menu.html',
      link: function($scope) {
        $scope.dropdownRight = $scope.right === 'true';
        $scope.renameTopic = function() {
          bootbox.prompt({
            title: 'Rename topic',
            value: $scope.topic.name,
            callback: function(name) {
              if (name && name.length && name !== $scope.topic.name) {
                var oldName = $scope.topic.name;
                $scope.topic.name = name;
                $scope.$apply(function() {
                  TopicFactory.update({
                    id: $scope.topic.id
                  }, $scope.topic, function(data) {
                    $scope.topic = data;
                  }, function(err) {
                    $scope.topic.name = oldName;
                    $scope.errors = err;
                  });
                });
              }
            }
          });
        };
      }
    };
  }]);

  app.directive('wordMenu', [function() {
    return {
      scope: {
        word: '=',
        right: '@'
      },
      restrict: 'E',
      templateUrl: 'html/directives/word-menu.html',
      link: function($scope) {
        $scope.dropdownRight = $scope.right === 'true';
      }
    };
  }]);

  app.directive('entityMenu', [function() {
    return {
      scope: {
        entity: '=',
        right: '@'
      },
      restrict: 'E',
      templateUrl: 'html/directives/entity-menu.html',
      link: function($scope) {
        $scope.dropdownRight = $scope.right === 'true';
      }
    };
  }]);

  app.directive('articleMenu', [function() {
    return {
      scope: {
        article: '=',
        right: '@'
      },
      restrict: 'E',
      templateUrl: 'html/directives/article-menu.html',
      link: function($scope) {
        $scope.dropdownRight = $scope.right === 'true';
      }
    };
  }]);

  app.directive('sortDir', [function() {
    return {
      scope: {
        ngModel: '='
      },
      restrict: 'E',
      replace: true,
      templateUrl: 'html/directives/sort-dir.html'
    };
  }]);

  app.directive('ngEnter', [function() {
    return {
      link: function($scope, $elem, $attrs) {
        $elem.bind("keydown keypress", function(event) {
          if (event.which === 13) {
            $scope.$apply(function() {
              $scope.$eval($attrs.ngEnter);
            });
            event.preventDefault();
          }
        });
      }
    };
  }]);

  app.directive('changePos', [function() {
    return {
      scope: {
        change: '='
      },
      link: function($scope) {
        $scope.changed = function() {
          var change = parseInt($scope.change);
          if (!isNaN(change)) {
            $scope.changeVal = change;
            if (change > 0)
              $scope.change = '+' + change;
          } else {
            $scope.changeVal = 0;
          }
        };

        $scope.$watch('change', $scope.changed);
      },
      templateUrl: 'html/directives/change-pos.html'
    };
  }]);

  app.directive('menuAffix', [function() {
    return {
      transclude: true,
      template: '<div class="menu-affix" ng-transclude></div><div class="affix-after"></div>',
      link: function($scope, $elem) {
        var elem = $elem.find('.menu-affix'),
          after = $elem.find('.affix-after');

        elem.affix({
          offset: {
            top: elem.offset().top - 50
          }
        });

        elem.on('affix.bs.affix', function() {
          after.css('height', elem.height());
        });

        elem.on('affix-top.bs.affix', function() {
          after.css('height', 0);
        });
      }
    };
  }]);

  app.directive('info', [function() {
    return {
      scope: {
        text: '@'
      },
      replace: true,
      template: '<i class="fa fa-info info" ng-attr-title="{{::text}}"></i>'
    };
  }]);

  app.directive('wordEvolution', [function() {
    return {
      scope: {
        topic: '=',
        chartId: '@'
      },
      replace: true,
      controller: 'WordEvolutionController',
      templateUrl: 'html/directives/word-evolution.html'
    };
  }]);

  app.directive('charSelector', [function() {
    return {
      replace: true,
      scope: {
        ngModel: '='
      },
      link: function($scope, $elem) {
        $elem.on('click', 'a', function() {
          var c = $(this).data('char');
          $scope.$apply(function() {
            $scope.ngModel = c;
          });
        });
      },
      templateUrl: 'html/directives/char-selector.html'
    };
  }]);

  app.directive('articlePopover', ['ArticleFactory', function(ArticleFactory) {
    return {
      scope: {
        id: '=',
        article: '='
      },
      link: function($scope) {
        $scope.$watch('id', function() {
          if(!$scope.id) {
            $scope.currentArticle = null;
            return;
          }

          ArticleFactory.get({
            id: $scope.id
          }, function(data) {
            $scope.currentArticle = data;
            $scope.currentArticleDate = $scope.currentArticle ? Vipra.formatDate($scope.currentArticle.date) : null;
          });
        });

        $scope.$watch('article', function() {
          $scope.currentArticle = $scope.article;
          $scope.currentArticleDate = $scope.article ? Vipra.formatDate($scope.currentArticle.date) : null;
        });
      },
      templateUrl: 'html/directives/article-popover.html'
    };
  }]);

})();