By Andrea Stagi, deveLover @ Nephila
(Stan Lee)
(Rolling Stones)
(Pink Floyd)
(Guns 'n' Roses)
https://github.com/nephila/ng-nephila
angular.module('ngNephila.filters.range', [])
.filter('nphRange', function(){
  return function(start, end, step) {
    var res = [];
    // DO STUFF
    return res;
  };
});angular.module('ngNephila.filters.range', [])
.filter('nphRange', function(){
  return function(start, end, step) {
    var res = [];
    var leftToRight = true;
    if (step < 1) {
      throw new Error('Step parameter must be >= 1');
    }
    step = ( step === undefined || step === null ) ? 1 : step;
    if (end === undefined || end === null) {
      end = start;
      start = 0;
    }
    if (start > end) {
      var aux = end;
      end = start;
      start = aux;
      leftToRight = false;
    }
    for (var i = start; i < end; i+=step) {
      if (leftToRight) {
        res.push(i);
      } else {
        res.unshift(i);
      }
    }
    return res;
  };
});describe('Filter: range', function () {
  beforeEach(module('ngNephila.filters.range'));
  var range;
  beforeEach(inject(function($filter) {
    range = $filter('nphRange');
  }));
  it('should return consider the step when present', function () {
    expect(range(6, 12, 2)).toEqual([6, 8, 10]);
    expect(range(12, 6, 2)).toEqual([10, 8, 6]);
  });
  it('has a range filter', function () {
    expect(range).not.toBeNull();
  });
  it('should raise an exeption if step < 1', function () {
    expect(function() {
      range(6, 12, -1);
    }).toThrow();
  });
});gulp.task('test-src', function () {
  return gulp.src(testFiles)
    .pipe(karma({
      configFile: 'karma.conf.js',
      action: 'run',
      browsers: ['Chrome']
    }));
});var testFiles = [
  'bower_components/moment/min/moment-with-locales.min.js',
  'bower_components/jquery/dist/jquery.min.js',
  'bower_components/angular/angular.min.js',
  'bower_components/angular-mocks/angular-mocks.js',
  'src/**/*.js',
  'template/**/*.html.js'
];gulp.task('travis-src', function () {
  return gulp.src(testFiles)
    .pipe(karma({
      configFile: 'karma.conf.js',
      action: 'run',
      reporters: ['dots', 'coverage', 'coveralls'],
      browsers: ['Firefox'],
      coverageReporter: {
        type: 'lcov',
        dir: 'coverage/',
        subdir: '.',
      }
    }));
});angular.module('ngNephila.services.pathJoin', [
  'ngNephila.filters.path'
])
.service('nphPathJoin', function(pathFilter) {
  // IMPLEMENT IT USING 'this'
});angular.module('ngNephila.services.pathJoin', [
  'ngNephila.filters.path'
])
.factory('nphPathJoin', function(pathFilter) {
  return function() {
    // IMPLEMENTATION
  };
});angular.module('ngNephila.services.pagination', [])
.provider('nphPagination', function paginationProvider() {
  var itemsPerPage = 0;
  this.setItemsPerPage = function (extItemsPerPage) {
    itemsPerPage = extItemsPerPage;
  };
  function PaginatorFactory() {
    this.getPaginator = function () {
      return new Paginator();
    };
  }
  function Paginator() {
    // Paginator IMPLEMENTATION
  }
  this.$get = function() {
    return new PaginatorFactory();
  };
});var app = angular.module('demo', ['ngNephila']);
app.config(function(nphPaginationProvider) {
  nphPaginationProvider.setItemsPerPage(5);
});angular.module('ngNephila.services.debounce', [])
.factory('nphDebounce', ['$timeout','$q', function($timeout, $q) {
  return function debounce(func, wait, immediate) {
    // IMPLEMENTATION
  };
}]);.
├── components
│   ├── module.js
│   └── test
├── filters
│   ├── module.js
│   ├── range.js
│   └── test
│       └── range.spec.js
├── module.js
└── services
    ├── module.js
    └── testangular.module('ngNephila.filters', [
  'ngNephila.filters.range',
  'ngNephila.filters.titlecase',
  'ngNephila.filters.stripHtml',
  'ngNephila.filters.strip',
  'ngNephila.filters.path'
]);angular.module('ngNephila', [
  'ngNephila.filters',
  'ngNephila.services',
  'ngNephila.components'
]);angular.module('ngNephila.filters', [
  'ngNephila.filters.range',
  'ngNephila.filters.titlecase',
  'ngNephila.filters.stripHtml',
  'ngNephila.filters.strip',
  'ngNephila.filters.path'
]);angular.module('ngNephila', [
  'ngNephila.filters',
  'ngNephila.services',
  'ngNephila.components'
]);<nph-paginator start="1" compress="2" number-of-items="numberOfItems"
on-page-change="pageChange(page)" next-label="Next" prev-label="Prev."
compress-label="...."></nph-paginator>angular.module('ngNephila.components.paginator', [
  'ngNephila.services.pagination',
  'ngNephila.filters.range',
  'ngNephila.tpls.paginator.paginator'
])
.directive('nphPaginator', [
  '$filter', 'nphPagination', function($filter, nphPagination) {
    return {
      restrict: 'E',
      // TO BE CONTINUED ...
    }
  }
]);<input nph-focus-me="true"></input>angular.module('ngNephila.components.focusMe',[])
.directive('nphFocusMe', ['$timeout', function($timeout) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      scope.$watch(attrs.nphFocusMe, function(value) {
        if(value === true) {
          $timeout(function() {
            element[0].focus();
          });
        }
      });
    }
  };
}]);$http.get(templateUrl, {cache: $templateCache})angular.module('ngNephila.components.paginator', [
    //......
])
.directive('nphPaginator', [
  '$filter', 'nphPagination', function($filter, nphPagination) {
    return {
      //......
      templateUrl: function(elem,attrs) {
        return attrs.templateUrl || 'template/paginator/paginator.html';
      },
      //......
    }
]);<ul>
  <li>
    <a href="" ng-click="paginator.prev()">{{prevLabel || "<<"}}</a>
  </li>
  <li ng-hide="canHide(i)" 
    ng-class="{active: i == paginator.getCurrentPage()}" 
    ng-repeat="i in pages">
    <a href="" ng-hide="isFirstCanHide(i)" 
       ng-click="paginator.goToPage(i)">{{i}}</a>
    <span ng-show="isFirstCanHide(i)">{{compressLabel || "..."}}</span>
  </li>
  <li>
    <a href="" ng-click="paginator.next()">{{nextLabel || ">>"}}</a>
  </li>
</ul>gulp.task('html2js', function () {
  return gulp.src('template/**/*.html')
    .pipe(html2js({
      moduleName: function (file) {
        var path = file.path.split('/'),
            folder = path[path.length - 2],
            fileName = path[path.length - 1].split('.')[0];
        var name = 'ngNephila.tpls.' + folder;
        return name + '.' + fileName;
      },
      prefix: "template/"
    }))
    .pipe(rename({
      extname: ".html.js"
    }))
    .pipe(gulp.dest('template'))
});(function(module) {
try {
  module = angular.module('ngNephila.tpls.paginator.paginator');
} catch (e) {
  module = angular.module('ngNephila.tpls.paginator.paginator', []);
}
module.run(['$templateCache', function($templateCache) {
  $templateCache.put('template/paginator/paginator.html',
    '<ul>\n' +
    '  <li>\n' +
    '    <a href="" ng-click="paginator.prev()">{{prevLabel || "<<"}}</a>\n' +
    '  </li>\n' +
    '  <li ng-hide="canHide(i)" ng-class="{active: i == paginator.getCurrentPage()}" ng-repeat="i in pages">\n' +
    '    <a href="" ng-hide="isFirstCanHide(i)" ng-click="paginator.goToPage(i)">{{i}}</a>\n' +
    '    <span ng-show="isFirstCanHide(i)">{{compressLabel || "..."}}</span>\n' +
    '  </li>\n' +
    '  <li>\n' +
    '    <a href="" ng-click="paginator.next()">{{nextLabel || ">>"}}</a>\n' +
    '  </li>\n' +
    '</ul>');
}]);
})();
})();angular.module('ngNephila.components.tabsaccordion', [])
.directive('nphTabsaccordion', function() {
  return {
    restrict: 'E',
    scope: {},
    transclude: true,
// ......<nph-tabsaccordion>
  <nph-tabheaders>
    <nph-tabheader selected="true" ref="tab1">
      Tab 1
    </nph-tabheader>
    <nph-tabheader ref="tab2">
      Tab 2
    </nph-tabheader>
  </nph-tabheaders>
  <nph-tabcontents>
    <nph-tabcontent ref="tab1">
      Content 1
    </nph-tabcontent>
    <nph-tabcontent ref="tab2">
      Content 2
    </nph-tabcontent>
  </nph-tabcontents>
</nph-tabsaccordion>angular.module('ngNephila.components.tabsaccordion', [])
.directive('nphTabsaccordion', function() {
  return {
    restrict: 'E',
    scope: {},
    transclude: true,
    replace: true,
// .......directive('nphTabheader', function() {
  return {
    scope: {
      ref: '@',
      selected: '='
    },
    require: '^nphTabsaccordion',
    restrict: 'E',
    transclude: true,
    replace: true,
    link: function(scope, element, attrs, tabsaccordion) {
      // .....
    },
    // ....
  };
})Make it modular!
Improvements all night long!
ES6 porting (next DjangoBeer sorry!)
Better demo page (...)
(Te Ende)
Twitter: @4stagi
Github: github.com/astagi
Email: a.stagi@nephila.it