diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..c77963f
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,54 @@
+{
+"maxerr": 50,
+"bitwise": true,
+"camelcase": false,
+"curly": true,
+"eqeqeq": true,
+"forin": true,
+"freeze": true,
+"immed": false,
+"indent": 4,
+"latedef": false,
+"newcap": false,
+"noarg": true,
+"noempty": true,
+"nonbsp": true,
+"nonew": false,
+"plusplus": false,
+"quotmark": false,
+"undef": true,
+"unused": true,
+"strict": true,
+"maxparams": false,
+"maxdepth": false,
+"maxstatements": false,
+"maxcomplexity": false,
+"maxlen": false,
+"varstmt": true,
+"asi": false,
+"boss": false,
+"debug": false,
+"eqnull": false,
+"esnext": true,
+"moz": false,
+"evil": false,
+"expr": false,
+"funcscope": false,
+"globalstrict": false,
+"iterator": false,
+"lastsemic": false,
+"laxbreak": false,
+"laxcomma": false,
+"loopfunc": false,
+"multistr": false,
+"noyield": false,
+"notypeof": false,
+"proto": false,
+"scripturl": false,
+"shadow": false,
+"sub": false,
+"supernew": false,
+"validthis": false,
+"node": true,
+"globals": {}
+}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..698f7cd
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,4 @@
+### 1.0.0-beta
+**2016-08-18**
+
+Initial Beta Pre-release
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..4d990e5
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (C) 2016 VHX, Inc. (https://vhx.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
index 0336fe1..1777c38 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,13 @@
# VHX Javascript API Client
-API applications can be created in the [VHX admin](https://www.vhx.tv/admin/platforms) or by emailing [api@vhx.tv](mailto:api@vhx.tv)
+Currently not ready for production use, but in Pre-Release. Publishable VHX API keys with limited scope will be required for use.
### Installation
-`npm install vhxjs`
+`npm install vhxjs@beta`
### Documentation
-Documentation, including a step-by-step tutorial is available on the [VHX Developer Docs ](http://dev.vhx.tv/api?javascript) site.
For Full API reference [go here](http://dev.vhx.tv/docs/api?javascript).
### Getting Started
@@ -23,17 +22,16 @@ Every resource method has two arguments. The first argument is an options object
```js
-// example customer create
-vhxjs.customers.list({
- email: 'customer@email.com',
- name: 'First Last'
-}, function(err, customer){
+// example collections request
+vhxjs.collections.all({
+ product: 'https://api.vhx.tv/products/1'
+}, function(err, collections){
// err, = error is false if no error occurred
- // customer = the created customer object
+ // collections = the response object
});
```
-### Resources & methods
+### Resources & Methods
products
* [`retrieve`](http://dev.vhx.tv/docs/api/?javascript#product-retrieve)
@@ -52,3 +50,46 @@ collections
* [`retrieve`](http://dev.vhx.tv/docs/api?javascript#collections-retrieve)
* [`all`](http://dev.vhx.tv/docs/api?javascript#collections-list)
* [`items`](http://dev.vhx.tv/docs/api?javascript#collection-items-list)
+
+
+### Pagination Methods
+Paginated resources will have helper methods available in the response object for conveniently requesting the next, previous, first, last, and specific pages.
+
+```javascript
+var collectionList;
+
+vhxjs.collections.all({
+ per_page: 25
+}, function(err, collections) {
+ collectionList = collections;
+})
+
+// example next page request with jquery
+$('.next-page').on('click', function() {
+ collectionList.nextPage(function(err, collections) {
+ // if you want the items and count to be concatenated
+ collectionList.merge(collections);
+
+ // if you just want the one page
+ collectionList = collections;
+ });
+})
+```
+
+* `nextPage(callback:Function)`
+Gets the next page in the request. If you are on the last page the *No more pages to request* error will be thrown.
+
+* `previousPage(callback:Function)`
+Gets the previous page in the request. If you are on the first page the *No previous pages to request* error will be thrown.
+
+* `firstPage(callback:Function)`
+Gets the first page in the request.
+
+* `lastPage(callback:Function)`
+Gets the last page in the request.
+
+* `goToPage(page:Integer, callback:Function)`
+Gets the specified page in the request. If a non-integer or page greater than pages available is requested the *You must pass a valid page number* error will be thrown.
+
+* `merge(response:Object)`
+Merges a page with previously requested page. It is recommended to use this when using the `nextPage` method in a "Load More" scenario where you are appending items to a growing cascade.
diff --git a/lib/paginate.js b/lib/paginate.js
new file mode 100644
index 0000000..fd4b83c
--- /dev/null
+++ b/lib/paginate.js
@@ -0,0 +1,79 @@
+'use strict';
+
+class Paginate {
+ constructor(resource, args) {
+ let _this = this;
+
+ _this.resource = resource;
+ _this.response = args.body;
+ _this.options = args.options;
+ _this.page = _this.options.page ? _this.options.page : 1;
+ _this.method = args.method;
+ _this.last = Math.ceil(args.body.total / (args.body.count * _this.page));
+
+ ['nextPage','previousPage','firstPage','lastPage'].map(function(key) {
+ _this.response[key] = function(callback) {
+ _this[key](_this, callback);
+ };
+ });
+
+ _this.response.goToPage = function(num, callback) {
+ _this.goToPage(_this, num, callback);
+ };
+
+ _this.response.merge = function(_this) {
+ _this._embedded[_this.object] = this._embedded[_this.object].concat(_this._embedded[_this.object]);
+ _this.count = this.count + _this.count;
+
+ return _this;
+ };
+ }
+
+ get() {
+ let _this = this;
+
+ return _this.response;
+ }
+
+ nextPage(_this, callback) {
+ _this.options.page = _this.page + 1;
+
+ if (_this.options.page > _this.last) {
+ throw 'No more pages to request';
+ }
+
+ _this.resource[_this.method](_this.options, callback);
+ }
+
+ previousPage(_this, callback) {
+ if (_this.page === 1) {
+ throw 'No previous pages to request';
+ }
+
+ _this.options.page = _this.page - 1;
+ _this.resource[_this.method](_this.options, callback);
+ }
+
+ firstPage(_this, callback) {
+ _this.options.page = 1;
+ _this.resource[_this.method](_this.options, callback);
+ }
+
+ lastPage(_this, callback) {
+ _this.options.page = _this.last;
+ _this.resource[_this.method](_this.options, callback);
+ }
+
+ goToPage(_this, num, callback) {
+ num = parseInt(num, 10);
+
+ if (num > 0 && num <= _this.last) {
+ _this.options.page = num;
+ return _this.resource[_this.method](_this.options, callback);
+ }
+
+ throw 'You must pass a valid page number';
+ }
+}
+
+module.exports = Paginate;
\ No newline at end of file
diff --git a/lib/resource.js b/lib/resource.js
index a6465ad..ca96281 100644
--- a/lib/resource.js
+++ b/lib/resource.js
@@ -1,7 +1,7 @@
'use strict';
const request = require('superagent');
-const defaults = require('./defaults');
+const paginate = require('./paginate');
class Resource {
constructor(api, path, methods, isToken) {
@@ -192,7 +192,10 @@ class Resource {
if (!err && response.statusCode >= 200 && response.statusCode < 300) {
_this.successHandler({
body: response.body || null,
- callback: args.callback
+ callback: args.callback,
+ options: args.options,
+ object: _this.path,
+ method: args.client_method
});
} else {
_this.errorHandler({
@@ -205,7 +208,17 @@ class Resource {
}
successHandler(args) {
- args.callback(false, args.body);
+ let response = args.body;
+
+ if (args.body.count && args.body.count < args.body.total) {
+ response = new paginate(this, args).get();
+ }
+
+ response.object = args.object;
+
+ if (args.callback) {
+ args.callback(false, response);
+ }
}
errorHandler(args) {
diff --git a/lib/vhx.js b/lib/vhx.js
index 1d6633e..d8bb201 100644
--- a/lib/vhx.js
+++ b/lib/vhx.js
@@ -1,5 +1,4 @@
import defaults from './defaults';
-import Resource from './resource';
import Collection from './resources/collections';
import Video from './resources/videos';
import Customer from './resources/customers';
@@ -32,7 +31,7 @@ class vhx {
host: defaults.HOST,
protocol: defaults.PROTOCOL,
timeout: defaults.TIMEOUT
- }
+ };
}
setToken() {
@@ -42,7 +41,7 @@ class vhx {
protocol: defaults.PROTOCOL,
timeout: defaults.TIMEOUT,
token_host: defaults.TOKEN_HOST
- }
+ };
}
prepareResources() {