doctype html html

head
  meta[http-equiv="Content-Type" content="text/html; charset=UTF-8"]
  link[href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"]
  link[href="http://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet"]
  script[src="https://code.jquery.com/jquery-2.1.4.js"]
  script[src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.js"]
  script[src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.js"]
  /script[src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"]
  /script[src="https://code.jquery.com/jquery-2.1.4.min.js"]
  /script[src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"]

  /script[src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.13.4/ui-bootstrap.min.js"]
  /script[src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.13.4/ui-bootstrap.js"]
  /script[src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.13.4/ui-bootstrap-tpls.min.js"]
  /script[src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.13.4/ui-bootstrap-tpls.js"]
  title
    | Blinkr
  meta[content="width=device-width, initial-scale=1" name="viewport"]
body
  div[ng-controller="ErrorCtrl"]
    .container
      h1
        | Blinkr
      p.lead
        | Blackbox testing for websites
      h2
        ' Pages
        .label.label-default>
          | {{numPages}}
        ' Errors
        .label.label-default
          | {{report.total}}
      .panel.panel-default
        .panel-heading
          h4
            a#control-filters[data-toggle="collapse" href="#filters"]
              i.fa.fa-caret-square-o-down
            |  Filters
        #filters.panel-collapse.collapse.in
          .panel-body
            form.row
              #severities.col-md-2
                .panel.panel-default
                  .panel-heading
                    .checkbox
                      label
                        ' Severity
                  .panel-body[ng-repeat="(key, value) in filters.severities"]
                    .checkbox
                      label>
                        input.type>[ng-model="filters.severities[key].enabled" type="checkbox"]
                        ' {{key}}
                      div[class="label label-{{key}}"]
                        ' {{value.count}}
              #category.col-md-5[style="padding-left:20px; border-left: 1px solid #ccc;"]
                .row
                  .col-md-12
                    .panel.panel-default
                      .panel-heading
                        .checkbox
                          label
                            ' Category
                      .panel-body[ng-repeat="(key, value) in filters.categories"]
                        .checkbox
                          label>
                            input.type[ng-model="filters.categories[key].enabled" type="checkbox"]
                            ' {{key}}
                          .label.label-default
                            | {{value.count}}
              #types.col-md-5[style="padding-left:20px; border-left: 1px solid #ccc;"]
                .row
                  .col-md-12
                    .panel.panel-default
                      .panel-heading
                        .checkbox
                          label>
                            ' Type
                      .panel-body[ng-repeat="(key, value) in filters.types"]
                        .checkbox
                          label>
                            input.type[ng-model="filters.types[key].enabled" type="checkbox"]
                            | {{key}}
                          .label.label-default
                            | {{value.count}}
      .text-center
        button.btn.btn-default.btn-lg[ng-disabled="currentPage == 0" ng-click="currentPage = currentPage - 1"] Previous
        '
          {{currentPage + 1}} / {{numberOfPages()}}
        button.btn.btn-default.btn-lg[ng-disabled="currentPage >= numberOfPages() - 1" ng-click="currentPage = currentPage + 1"] Next
        br
        br
      .page[ng-repeat="page in report.pages | showPage:filters | startFrom:currentPage * limitSize | limitTo:limitSize"]
        div[class="panel panel-{{page.max_severity}}"]
          .panel-heading
            .panel-title
              ul.list-inline
                li
                  a>[data-toggle="collapse" href="#"]
                    i.fa.fa-caret-square-o-right
                  | {{page.url}} ({{page.errors.length}} total errors)
                li
                  a[href="{{page.url}}" target="_blank"]
                    i.fa.fa-external-link
                li
                  a[href="{{page.url}}" target="_blank"]
                    i.fa.fa-file-code-o
          .panel-body.collapse.panel-collapse
            ul
              li.list-group-item.error[ng-repeat="(i,page_error) in page.errors | displayError:filters"]
                i.fa.fa-2x.fa-bookmark-o.pull-left
                div[class="pull-right label label-{{page_error.severity}}"]
                  | {{page_error.code}} {{page_error.message}}
                div
                  ' {{page_error.title}}
                  a[href="{{page_error.title}}" target="_blank" ng-if="page_error.title.startsWith('http')"]
                    i.fa.fa-external-link
                pre
                  | {{page_error.snippet}}
  javascript:
    var blinkr = angular.module('blinkr', []);
    blinkr.factory('report', function reportFactory() {
      return #{{errors}};
    });

    blinkr.controller("ErrorCtrl", ['$scope', 'report', function ($scope, report) {
      $scope.report = report;
      $scope.filters = {severities: {}, categories: {}, types: {}};
      $scope.report = report;
      $scope.numPages = report.pages.length;
      $scope.filteredNumPages = 0;
      $scope.currentPage = 0;
      $scope.limitSize = 25;
      window.scope = $scope;

      Object.keys($scope.report.severity).forEach(function (s) {
        $scope.filters.severities[s] = {enabled: false, count: report.severity[s].count};
      });

      Object.keys($scope.report.category).forEach(function (c) {
        $scope.filters.categories[c] = {enabled: false, count: report.category[c].count};
      });

      Object.keys($scope.report.type).forEach(function (t) {
        $scope.filters.types[t] = {enabled: false, count: report.type[t].count};
      });

      $scope.numberOfPages = function () {
        return Math.ceil($scope.filteredNumPages / $scope.limitSize);
      }
    }]);

    blinkr.filter('startFrom', function () {
      return function (input, start) {
        start = +start; //parse to int
        return input.slice(start);
      }
    });

    blinkr.filter('displayError', function () {
      return function (errors, filters) {
        var returned_errors = [];
        errors.forEach(function (error) {
          if (showError(error, filters)) {
            returned_errors.push(error);
          }
        });
        panelBind();
        return returned_errors;
      }
    });

    blinkr.filter('showPage', function () {
      return function (all_pages, filters) {
        var pages = [];
        all_pages.forEach(function (page) {
          if ($.arrayIntersect(enabledFilters(filters, 'categories'), page.categories).length > 0) {
            pages.push(page);
          } else if ($.arrayIntersect(enabledFilters(filters, 'types'), page.types).length > 0) {
            pages.push(page);
          } else if ($.arrayIntersect(enabledFilters(filters, 'severities'), page.severities).length > 0) {
            pages.push(page);
          }
        });
        scope.filteredNumPages = pages.length;
        return pages;
      }
    });

    function enabledFilters(filters, filterName) {
      var enabled = [];
      Object.keys(filters[filterName]).forEach(function (f) {
        if (filters[filterName][f].enabled) {
          enabled.push(f);
        }
      });
      return enabled;
    }

    function showError(error, filters) {
      var categories = enabledFilters(filters, 'categories'),
              severities = enabledFilters(filters, 'severities'),
              types = enabledFilters(filters, 'types'),
              possibleReturn = false;

      if (categories.length > 0 && categories.indexOf(error.category) > -1) {
        possibleReturn = true;
      }

      if (possibleReturn) {
        if (severities.length > 0) {
          possibleReturn = severities.indexOf(error.severity) > -1;
        }
      } else {
        if (severities.length > 0) {
          possibleReturn = severities.indexOf(error.severity) > -1;
        }
      }

      if (possibleReturn) {
        if (types.length > 0) {
          possibleReturn = !!(types.length > 0 && types.indexOf(error.type) > -1);
        }
      } else {
        if (types.length > 0) {
          possibleReturn = !!(types.length > 0 && types.indexOf(error.type) > -1);
        }
      }

      return possibleReturn;
    }

    window.panelBind = function () {
      $('.panel-title').find('a[data-toggle=collapse]').on('click', function (e) {
        e.preventDefault();
        var target = $(this).parents('.panel').find('.panel-collapse');
        target.collapse('toggle');
      });
      $('.page').find('panel-collapse').collapse({toggle: false});
    };

    angular.element(document).ready(function () {
      panelBind();
    });

    $.arrayIntersect = function (a, b) {
      return $.grep(a, function (i) {
        return $.inArray(i, b) > -1;
      });
    };