Skip to content

Commit

Permalink
Pristine, mapping and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
christianalfoni committed Jan 21, 2015
1 parent a008b1c commit 15b6df9
Show file tree
Hide file tree
Showing 33 changed files with 46,868 additions and 111 deletions.
32 changes: 3 additions & 29 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,30 +1,4 @@
# Logs
logs
*.log

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directory
# Commenting this out is preferred by some people, see
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
node_modules

# Users Environment Variables
.lock-wscript
.DS_Store
build/
build/index.html
build/test.js
node_modules
142 changes: 89 additions & 53 deletions Gulpfile.js
Original file line number Diff line number Diff line change
@@ -1,94 +1,130 @@
var gulp = require('gulp');
var source = require('vinyl-source-stream'); // Used to stream bundle for further handling
var browserify = require('browserify');
var watchify = require('watchify');
var source = require('vinyl-source-stream');
var reactify = require('reactify');
var gulpif = require('gulp-if');
var uglify = require('gulp-uglify');
var streamify = require('gulp-streamify');
var notify = require('gulp-notify');
var gutil = require('gulp-util');
var package = require('./package.json');
var shell = require('gulp-shell');
var reactify = require('reactify');
var livereload = require('gulp-livereload');
var glob = require('glob');
var jasminePhantomJs = require('gulp-jasmine2-phantomjs');
var fs = require('fs');

var dependencies = ['react'];

var browserifyTask = function (options) {

// Our app bundler
var appBundler = browserify({
entries: [options.src],
transform: [reactify],
debug: options.development,
cache: {},
packageCache: {},
fullPaths: options.development
});

// The task that handles both development and deployment
var runBrowserifyTask = function (options) {

// This bundle is for our application
var bundler = browserify({
debug: options.debug, // Need that sourcemapping
standalone: 'Formsy',
// These options are just for Watchify
cache: {}, packageCache: {}, fullPaths: options.watch
})
.require(require.resolve('./src/main.js'), { entry: true })
.transform(reactify) // Transform JSX
.external('react');

// The actual rebundle process
appBundler.external(dependencies);

// The rebundle process
var rebundle = function () {
var start = Date.now();
bundler.bundle()
var fileName = options.uglify ? 'formsy-react.min.js' : 'formsy-react.js';
console.log('Building APP bundle');
appBundler.bundle()
.on('error', gutil.log)
.pipe(source(options.name))
.pipe(source(fileName))
.pipe(gulpif(options.uglify, streamify(uglify())))
.pipe(gulp.dest(options.dest))
.pipe(notify(function () {
console.log('APP bundle built in ' + (Date.now() - start) + 'ms');

/*
// Fix for requirejs
var fs = require('fs');
var file = fs.readFileSync(options.dest + '/' + options.name).toString();
var file = fs.readFileSync(options.dest + '/' + fileName).toString();
file = file.replace('define([],e)', 'define(["react"],e)');
fs.writeFileSync(options.dest + '/' + options.name, file);

console.log('Built in ' + (Date.now() - start) + 'ms');

fs.writeFileSync(options.dest + '/' + fileName, file);
*/
}));

};

// Fire up Watchify when developing
if (options.watch) {
bundler = watchify(bundler);
bundler.on('update', rebundle);
if (options.development) {
appBundler = watchify(appBundler);
appBundler.on('update', rebundle);
}

return rebundle();
rebundle();

// We create a separate bundle for our dependencies as they
// should not rebundle on file changes. This only happens when
// we develop. When deploying the dependencies will be included
// in the application bundle
if (options.development) {

var testFiles = glob.sync('./specs/**/*-spec.js');
var testBundler = browserify({
entries: testFiles,
debug: true,
transform: [reactify],
cache: {},
packageCache: {},
fullPaths: true
});

testBundler.external(dependencies);

var rebundleTests = function () {
var start = Date.now();
console.log('Building TEST bundle');
testBundler.bundle()
.on('error', gutil.log)
.pipe(source('specs.js'))
.pipe(gulp.dest(options.dest))
.pipe(livereload())
.pipe(notify(function () {
console.log('TEST bundle built in ' + (Date.now() - start) + 'ms');
}));
};

testBundler = watchify(testBundler);
testBundler.on('update', rebundleTests);
rebundleTests();

};
}

}

// Starts our development workflow
gulp.task('default', function () {

runBrowserifyTask({
watch: true,
dest: './build',
uglify: false,
debug: true,
name: 'formsy-react.js'
livereload.listen({ basePath: 'specs' });
browserifyTask({
development: true,
src: './src/main.js',
dest: './build'
});

});

gulp.task('deploy', function () {

runBrowserifyTask({
watch: false,
dest: './releases',
uglify: true,
debug: false,
name: 'formsy-react.min.js'
browserifyTask({
development: false,
src: './src/main.js',
dest: './release'
});

runBrowserifyTask({
watch: false,
dest: './releases',
uglify: false,
debug: false,
name: 'formsy-react.js'
browserifyTask({
development: false,
src: './src/main.js',
dest: './release',
uglify: true
});

});

gulp.task('test', shell.task([
'./node_modules/.bin/jasmine-node ./specs --autotest --watch ./src --color'
]));
57 changes: 55 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ A form input builder and validator for React JS
- [url](#url)
- [method](#method)
- [contentType](#contenttype)
- [mapping](#mapping)
- [onSuccess()](#onsuccess)
- [onSubmit()](#onsubmit)
- [onSubmitted()](#onsubmitted)
Expand All @@ -36,6 +37,7 @@ A form input builder and validator for React JS
- [isRequired()](#isrequired)
- [showRequired()](#showrequired)
- [showError()](#showerror)
- [isPristine()](#ispristine)
- [Formsy.addValidationRule](#formsyaddvalidationrule)
- [Validators](#validators)

Expand Down Expand Up @@ -63,6 +65,13 @@ The main concept is that forms, inputs and validation is done very differently a

## <a name="changes">Changes</a>

**0.6.0**
- **onSubmit()** now has the same signature regardless of passing url attribute or not
- **isPristine()** is a new method to handle "touched" form elements (thanks @FoxxMD)
- Mapping attribute to pass a function that maps input values to new structure. The new structure is either passed to *onSubmit* or to the server when using a url attribute (thanks for feedback @MattAitchison)
- Added default "equalsField" validation rule
- Lots of tests!

**0.5.2**
- Fixed bug with handlers in ajax requests (Thanks @smokku)

Expand Down Expand Up @@ -214,9 +223,11 @@ Takes a function to run when the server has responded with a success http status
```html
<Formsy.Form url="/users" onSubmit={this.showFormLoader}></Formsy.Form>
```
Takes a function to run when the submit button has been clicked. The first argument is the data of the form. The second argument will reset the form. The third argument will invalidate the form by taking an object that maps to inputs. E.g. `{email: "This email is taken"}`. Resetting or invalidating the form will cause **setState** to run on the form element component.
Takes a function to run when the submit button has been clicked.

The first argument is the data of the form. The second argument will reset the form. The third argument will invalidate the form by taking an object that maps to inputs. E.g. `{email: "This email is taken"}`. Resetting or invalidating the form will cause **setState** to run on the form element component.

**note!** When resetting the form the form elements needs to bind its current value using the *getValue* method. That will empty for example an input.
**note!** If you do not pass a url attribute this handler is where you would manually do your ajax request.

#### <a name="onsubmitted">onSubmitted()</a>
```html
Expand Down Expand Up @@ -297,6 +308,7 @@ Gets the current value of the form input component.
#### <a name="setvalue">setValue(value)</a>
```javascript
var MyInput = React.createClass({
mixins: [Formsy.Mixin],
changeValue: function (event) {
this.setValue(event.currentTarget.value);
},
Expand All @@ -312,6 +324,7 @@ Sets the value of your form input component. Notice that it does not have to be
#### <a name="hasvalue">hasValue()</a>
```javascript
var MyInput = React.createClass({
mixins: [Formsy.Mixin],
changeValue: function (event) {
this.setValue(event.currentTarget.value);
},
Expand All @@ -330,6 +343,7 @@ The hasValue() method helps you identify if there actually is a value or not. Th
#### <a name="resetvalue">resetValue()</a>
```javascript
var MyInput = React.createClass({
mixins: [Formsy.Mixin],
changeValue: function (event) {
this.setValue(event.currentTarget.value);
},
Expand All @@ -348,6 +362,7 @@ Resets to empty value. This will run a **setState()** on the component and do a
#### <a name="geterrormessage">getErrorMessage()</a>
```javascript
var MyInput = React.createClass({
mixins: [Formsy.Mixin],
changeValue: function (event) {
this.setValue(event.currentTarget.value);
},
Expand All @@ -366,6 +381,7 @@ Will return the server error mapped to the form input component or return the va
#### <a name="isvalid">isValid()</a>
```javascript
var MyInput = React.createClass({
mixins: [Formsy.Mixin],
changeValue: function (event) {
this.setValue(event.currentTarget.value);
},
Expand All @@ -386,6 +402,7 @@ Returns the valid state of the form input component.
#### <a name="isrequired">isRequired()</a>
```javascript
var MyInput = React.createClass({
mixins: [Formsy.Mixin],
changeValue: function (event) {
this.setValue(event.currentTarget.value);
},
Expand All @@ -405,6 +422,7 @@ Returns true if the required property has been passed.
#### <a name="showrequired">showRequired()</a>
```javascript
var MyInput = React.createClass({
mixins: [Formsy.Mixin],
changeValue: function (event) {
this.setValue(event.currentTarget.value);
},
Expand All @@ -424,6 +442,7 @@ Lets you check if the form input component should indicate if it is a required f
#### <a name="showerror">showError()</a>
```javascript
var MyInput = React.createClass({
mixins: [Formsy.Mixin],
changeValue: function (event) {
this.setValue(event.currentTarget.value);
},
Expand All @@ -440,6 +459,28 @@ var MyInput = React.createClass({
```
Lets you check if the form input component should indicate if there is an error. This happens if there is a form input component value and it is invalid or if a server error is received.

#### <a name="ispristine">isPristine()</a>
```javascript
var MyInput = React.createClass({
mixins: [Formsy.Mixin],
changeValue: function (event) {
this.setValue(event.currentTarget.value);
},
render: function () {
return (
<div>
<input type="text" onChange={this.changeValue} value={this.getValue()}/>
<span>{this.isPristine() ? 'You have not touched this yet' : ''}</span>
</div>
);
}
});
```
By default all formsy input elements are pristine, which means they are not "touched". As soon as the **setValue** method is run it will no longer be pristine.

**note!** When the form is reset, using the resetForm callback function on **onSubmit** the inputs are not reset to pristine.


### <a name="formsyaddvalidationrule">Formsy.addValidationRule(name, ruleFunc)</a>
An example:
```javascript
Expand Down Expand Up @@ -528,6 +569,18 @@ Returns true if the value length is the equal or more than minimum and equal or
```
Return true if the value from input component matches value passed (==).

**equalsField:fieldName**
```html
<MyInputComponent name="password"/>
<MyInputComponent name="repeated_password" validations="equalsField:password"/>
```
Return true if the value from input component matches value passed (==).

## Run tests
- Run `gulp`
- Run a server in `build` folder
- Go to `localhost/testrunner.html` (live reload)

License
-------

Expand Down
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "formsy-react",
"version": "0.5.2",
"version": "0.6.0",
"main": "src/main.js",
"dependencies": {
"react": "^0.11.2"
Expand Down
Loading

0 comments on commit 15b6df9

Please sign in to comment.