Skip to content
This repository has been archived by the owner on Nov 14, 2018. It is now read-only.

Commit

Permalink
Introducing Flux store.
Browse files Browse the repository at this point in the history
  • Loading branch information
n1k0 committed Feb 7, 2015
1 parent bd9e5d0 commit ff1a536
Show file tree
Hide file tree
Showing 22 changed files with 683 additions and 161 deletions.
1 change: 0 additions & 1 deletion .jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
"immed": false,
"indent": 2,
"latedef": true,
"maxlen": 120,
"newcap": false,
"node": true,
"strict": true,
Expand Down
3 changes: 0 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ language: node_js
sudo: false
node_js:
- '0.10'
env:
global:
secure: LE0ESSk4xUUZUJafYGYm2jT+OEoXZciqZmLNmSHyx6l0SSMn/gwIayz3YLQ05MBg4X74m6FOU8niTa8b3KhGDk/jOXAU2tkGtfUsbxPqjK/DwH7nY5+kWGHFkmJgltjXAyIZUCYYbIeEmpCV0HEHEHjoIHxmrgL2lHGfhEiyhvg=
before_install:
- export CHROME_BIN=chromium-browser
- export DISPLAY=:99.0
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ Required nodejs v0.10.29+ and npm v2.1.0+.
Configuration
-------------

TODO
You can configure the client using the following environment variables:

- `READINGLIST_SERVER_BASEURL`: the Readinglist server base URL; default: `http://0.0.0.0:8000/v0`

Local dev server
----------------
Expand Down
31 changes: 15 additions & 16 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
"use strict";

var gulp = require("gulp");
var fs = require("fs");
var browserify = require('browserify');
var watchify = require('watchify');
var source = require('vinyl-source-stream');
Expand Down Expand Up @@ -31,8 +30,8 @@ var opt = {
"src/index.html"
],
app: {
src: "src/js/main.js",
dest: "app.js"
src: "./src/js/main.js",
dest: "bundle.js"
},
vendors: "vendors.js",
karmaConfigPath: __dirname + "/karma.conf.js"
Expand Down Expand Up @@ -62,20 +61,20 @@ gulp.task("assets:css", function() {
gulp.task("js", ["js:vendors", "js:app"]);

gulp.task("js:app", ["js:vendors"], function() {
return browserify("./" + opt.app.src)
return browserify(opt.app.src)
.external("react/addons")
.external("docbrown")
.transform(to5ify)
.transform("reactify")
.external("react")
.external("react-bootstrap")
.bundle()
.pipe(source(opt.app.dest))
.pipe(gulp.dest(opt.outputFolder + "/js"));
});

gulp.task("js:vendors", function() {
return browserify()
.require("react")
.require("react-bootstrap")
.require("react/addons")
.require("docbrown")
.bundle()
.pipe(source(opt.vendors))
.pipe(gulp.dest(opt.outputFolder + "/js"));
Expand Down Expand Up @@ -117,21 +116,21 @@ gulp.task("tdd", function(done) {
/**
* Watchify
*/
gulp.task("watchify", function(){
var b = browserify( "./" + opt.app.src , watchify.args)
.transform("reactify")
gulp.task("watchify", function() {
var b = browserify(opt.app.src, watchify.args)
.external("react/addons")
.external("docbrown")
.transform(to5ify)
.external("react")
.external("react-bootstrap");
.transform("reactify");

function updateBundle(w){
function updateBundle(w) {
return w.bundle()
.pipe(source(opt.app.dest))
.pipe(gulp.dest(opt.outputFolder + "/js"));
}

var watcher= watchify(b);
watcher.on("update", function(){
watcher.on("update", function() {
updateBundle(watcher);
});

Expand All @@ -142,7 +141,7 @@ gulp.task("watchify", function(){
* Watch task
* Launch a server with livereload
*/
gulp.task("watch", ["assets","js:vendors", "watchify"], function() {
gulp.task("watch", ["assets", "js:vendors", "watchify"], function() {
gulp.watch(opt.cssAssets, ["assets:css"]);
gulp.watch(opt.fontAssets, ["assets:fonts"]);
gulp.watch(opt.htmlAssets, ["assets:html"]);
Expand Down
14 changes: 7 additions & 7 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,31 @@ module.exports = function(config) {
mocha: {
reporter: "html", // change Karma"s debug.html to the mocha web reporter
ui: "bdd",
bail: true
bail: false
}
},

// list of files / patterns to load in the browser
files: [
"src/js/app.js",
"src/test/*_test.js"
//{pattern: "node_modules/docbrown/index.js", watched: true, served: false, included: false},
"src/js/**/*.js",
"src/test/index.js"
],

// list of files to exclude
exclude: [
"src/**/main.js"
"src/js/main.js"
],

// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
"src/**/*.js": ["browserify"],
"test/**/*.js": ["browserify"]
"src/**/*.js": ["browserify"]
},

browserify: {
debug: true,
transform: ["reactify", "6to5ify"]
transform: ["6to5ify", "reactify"]
},

// test results reporter to use
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@
"6to5": "^3.0.11",
"bootstrap": "^3.3.2",
"browserify": "^8.1.*",
"docbrown": "^0.5.*",
"gulp": "^3.8.*",
"gulp-uglify": "^1.1.*",
"gulp-webserver": "^0.9.*",
"react": "0.12.2",
"react-bootstrap": "^0.13.*",
"reactify": "^1.0.*",
"rest": "^1.3.0",
"vinyl-source-stream": "^1.0.*",
Expand All @@ -40,6 +40,7 @@
"devDependencies": {
"6to5ify": "^4.0.*",
"chai": "latest",
"gulp-sourcemaps": "^1.3.0",
"jsxhint": "latest",
"karma": "^0.12.*",
"karma-6to5-preprocessor": "^3.0.*",
Expand Down
2 changes: 1 addition & 1 deletion src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
<body>
<div id="app"></div>
<script src="js/vendors.js"></script>
<script src="js/app.js"></script>
<script src="js/bundle.js"></script>
</body>
</html>
71 changes: 43 additions & 28 deletions src/js/api.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
"use strict";

var rest = require("rest");
var pathPrefix = require("rest/interceptor/pathPrefix");
var mime = require("rest/interceptor/mime");
var errorCode = require("rest/interceptor/errorCode");
var defaultRequest = require("rest/interceptor/defaultRequest");
var hateoas = require("rest/interceptor/hateoas");
import rest from "rest";
import pathPrefix from "rest/interceptor/pathPrefix";
import mime from "rest/interceptor/mime";
import errorCode from "rest/interceptor/errorCode";
import defaultRequest from "rest/interceptor/defaultRequest";
import hateoas from "rest/interceptor/hateoas";
import basicAuth from "rest/interceptor/basicAuth";

class API {
/**
* Readinglist server REST API client.
* https://github.com/mozilla-services/readinglist/wiki/API-Design-proposal
*/
export default class API {
constructor(baseUrl, options={}) {
this.baseUrl = baseUrl;
this.client = options.client || rest
.wrap(pathPrefix, {prefix: this.baseUrl})
.wrap(errorCode, {code: 400})
.wrap(defaultRequest, {headers: {"X-Requested-With": "readinglist-client"}})
.wrap(mime, {mime: "application/json;encoding=UTF-8"})
.wrap(hateoas);
this.client = options.client || this.createClient();
}

/**
Expand All @@ -24,17 +24,31 @@ class API {
* @return {Promise} The wrapped promise.
*/
_wrap(promise) {
return promise.catch(function(res) {
// Only expose the error entity object, in the following form:
return promise.catch(res => {
if (!res.entity || res.error === "loaderror") {
throw new Error("Server seems to be down");
}
// res.entity is in the following form:
// {"errno":104,
// "message":"Please authenticate yourself to use this endpoint.",
// "code":401,
// "error":"Unauthorized"}
throw res.entity;
throw Object.assign(new Error(), res.entity);
}).then(res => {
// Get rid of the .entity intermediate property.
return res.entity;
});
//.done(function(res) {
// return res.entity;
// })
}

createClient() {
return rest
.wrap(pathPrefix, {prefix: this.baseUrl})
.wrap(errorCode, {code: 400})
.wrap(defaultRequest, {headers: {"X-Requested-With": "readinglist-client"}})
.wrap(mime, {mime: "application/json;encoding=UTF-8"})
.wrap(hateoas)
// XXX fix this
.wrap(basicAuth, {username: "niko", password: "niko"});
}

/**
Expand All @@ -58,11 +72,7 @@ class API {
* @return {Promise}
*/
createArticle(fields) {
return this._wrap(this.client({
method: "POST",
path: "/articles",
entity: JSON.stringify(fields)
}));
return this._wrap(this.client({method: "POST", path: "/articles", entity: fields}));
}

/**
Expand All @@ -71,7 +81,14 @@ class API {
* @return {Promise}
*/
listArticles(params={}) {
return this._wrap(this.client({path: "/articles"}));
var q = {
unread: true,
_sort: "-last_modified"
};
return this._wrap(this.client({
path: "/articles",
params: q
})).then(res => res.items);
}

/**
Expand All @@ -91,9 +108,7 @@ class API {
deleteArticle(params={}) {
return this._wrap(this.client({
method: "DELETE",
path: `/article/${params.id}`
path: `/articles/${params.id}`
}));
}
}

module.exports = API;
25 changes: 0 additions & 25 deletions src/js/app.js

This file was deleted.

14 changes: 14 additions & 0 deletions src/js/components/Alert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"use strict";

import React from "react";

export default React.createClass({
render: function() {
return (
<div className="alert alert-warning">
<p><strong>{this.props.title}</strong></p>
<div>{this.props.children}</div>
</div>
);
}
});
46 changes: 46 additions & 0 deletions src/js/components/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"use strict";

// Load 6to5 polyfills http://6to5.org/docs/usage/polyfill/
import "6to5/polyfill";

import React from "react/addons";
import DocBrown from "docbrown";
import { ArticleActions, stores } from "../flux";

import Alert from "./Alert";
import ArticleForm from "./ArticleForm";
import ArticleList from "./ArticleList";

export default React.createClass({
mixins: [DocBrown.storeMixin(stores.getter("articleStore"))],

componentDidMount: function() {
ArticleActions.list();
},

renderError: function() {
if (!this.state.error) return;
return (
<Alert title="Error">
<p>{this.state.error.message}</p>
</Alert>
);
},

render: function() {
return (
<div className="container-fluid">
<h1>Readinglist</h1>
{this.renderError()}
<div className="row">
<div className="col-md-3">
<ArticleList articles={this.state.articles} />
</div>
<div className="col-md-9">
<ArticleForm />
</div>
</div>
</div>
);
}
});
Loading

0 comments on commit ff1a536

Please sign in to comment.