Skip to content

Commit

Permalink
Merge pull request #29 from bboyle/css3-transitions
Browse files Browse the repository at this point in the history
update for html5 + css3
  • Loading branch information
bboyle committed Feb 27, 2015
2 parents 4344e79 + 33d2a9b commit 3e27129
Show file tree
Hide file tree
Showing 19 changed files with 328 additions and 218 deletions.
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ node_js:
before_script:
- npm install -g grunt-cli
- npm install -g bower
- bower install
- bower install
script:
- npm run-script test-on-travis
91 changes: 75 additions & 16 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,26 @@ module.exports = function( grunt ) {
grunt.initConfig({
// Metadata.
pkg: grunt.file.readJSON( 'package.json' ),
banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
title: '<%= pkg.title || pkg.name %> - v<%= pkg.version %>',
buildNumber: process.env.TRAVIS_BUILD_ID || grunt.template.today( 'isoUtcDateTime' ),
banner: '/*! <%= title %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %>\n' +
'<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
'* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',

browsers: [
{ browserName: 'Internet Explorer' },
{ browserName: 'Chrome' },
{ browserName: 'iPhone' },
{ browserName: 'android' },
{ browserName: 'Firefox' },
// old IE
{ browserName: 'Internet Explorer', version: '9' },
{ browserName: 'Internet Explorer', version: '8' },
{ browserName: 'Internet Explorer', version: '6' }
],

// Task configuration.
clean: {
files: [ 'dist' ]
Expand Down Expand Up @@ -51,27 +66,69 @@ module.exports = function( grunt ) {
jquery: {
options: {
urls: [
'http://localhost:8000/test/events.html?jquery=1.4.4',
'http://localhost:8000/test/instructions.html?jquery=1.4.4',
'http://localhost:8000/test/plugin.html?jquery=1.4.4',
'http://localhost:8000/test/relevantWhen.html?jquery=1.4.4',
'http://localhost:8000/test/ui.html?jquery=1.4.4',
'http://127.0.0.1:8000/test/events.html?jquery=1.4.4',
'http://127.0.0.1:8000/test/instructions.html?jquery=1.4.4',
'http://127.0.0.1:8000/test/plugin.html?jquery=1.4.4',
'http://127.0.0.1:8000/test/relevantWhen.html?jquery=1.4.4',
'http://127.0.0.1:8000/test/ui.html?jquery=1.4.4',
// 1.7.2
'http://localhost:8000/test/events.html?jquery=1.7.2',
'http://localhost:8000/test/instructions.html?jquery=1.7.2',
'http://localhost:8000/test/plugin.html?jquery=1.7.2',
'http://localhost:8000/test/relevantWhen.html?jquery=1.7.2',
'http://localhost:8000/test/ui.html?jquery=1.7.2',
'http://127.0.0.1:8000/test/events.html?jquery=1.7.2',
'http://127.0.0.1:8000/test/instructions.html?jquery=1.7.2',
'http://127.0.0.1:8000/test/plugin.html?jquery=1.7.2',
'http://127.0.0.1:8000/test/relevantWhen.html?jquery=1.7.2',
'http://127.0.0.1:8000/test/ui.html?jquery=1.7.2',
// 2.1.0
'http://localhost:8000/test/events.html?jquery=2.1.0',
'http://localhost:8000/test/instructions.html?jquery=2.1.0',
'http://localhost:8000/test/plugin.html?jquery=2.1.0',
'http://localhost:8000/test/relevantWhen.html?jquery=2.1.0',
'http://localhost:8000/test/ui.html?jquery=2.1.0',
'http://127.0.0.1:8000/test/events.html?jquery=2.1.0',
'http://127.0.0.1:8000/test/instructions.html?jquery=2.1.0',
'http://127.0.0.1:8000/test/plugin.html?jquery=2.1.0',
'http://127.0.0.1:8000/test/relevantWhen.html?jquery=2.1.0',
'http://127.0.0.1:8000/test/ui.html?jquery=2.1.0',
]
}
}
},
'saucelabs-qunit': {
events: {
options: {
testname: 'events - <%= title %>',
build: '<%= buildNumber %>',
urls: [ 'http://127.0.0.1:8000/test/events.html?jquery=1.7.2' ],
browsers: '<%= browsers %>'
}
},
instructions: {
options: {
testname: 'instructions - <%= title %>',
build: '<%= buildNumber %>',
urls: [ 'http://127.0.0.1:8000/test/instructions.html?jquery=1.7.2' ],
browsers: '<%= browsers %>'
}
},
plugin: {
options: {
testname: 'plugin - <%= title %>',
build: '<%= buildNumber %>',
urls: [ 'http://127.0.0.1:8000/test/plugin.html?jquery=1.7.2' ],
browsers: '<%= browsers %>'
}
},
relevantWhen: {
options: {
testname: 'relevantWhen - <%= title %>',
build: '<%= buildNumber %>',
urls: [ 'http://127.0.0.1:8000/test/relevantWhen.html?jquery=1.7.2' ],
browsers: '<%= browsers %>'
}
},
ui: {
options: {
testname: 'ui - <%= title %>',
build: '<%= buildNumber %>',
urls: [ 'http://127.0.0.1:8000/test/ui.html?jquery=1.7.2' ],
browsers: '<%= browsers %>'
}
},
},
jshint: {
gruntfile: {
options: {
Expand Down Expand Up @@ -114,11 +171,13 @@ module.exports = function( grunt ) {
grunt.loadNpmTasks( 'grunt-contrib-uglify' );
grunt.loadNpmTasks( 'grunt-contrib-connect' );
grunt.loadNpmTasks( 'grunt-contrib-qunit' );
grunt.loadNpmTasks( 'grunt-saucelabs' );
grunt.loadNpmTasks( 'grunt-contrib-jshint' );
grunt.loadNpmTasks( 'grunt-contrib-watch' );

// Default task.
grunt.registerTask( 'test', [ 'jshint', 'connect', 'qunit' ]);
grunt.registerTask( 'test-remote', [ 'jshint', 'qunit:unit', 'connect', 'clean', 'saucelabs-qunit' ]);
grunt.registerTask( 'produce', [ 'clean', 'concat', 'uglify' ]);
grunt.registerTask( 'default', [ 'test', 'produce' ]);

Expand Down
65 changes: 56 additions & 9 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,73 @@ indicates an element should be made irrelevant (hidden). No change for irrelevan
2. removes `@hidden` attribute
3. removes `aria-hidden`
4. shows the element (uses a `slideDown` transition)
5. fires event `relevant-done`

## .relevance( 'hide' )

1. hides element (no animation, hiding is immediate)
2. disables descendent form fields and self (if a form field)
3. adds `@hidden` attribute
4. adds `aria-hidden`
5. fires event `irrelevant-done`

## Events

| Event name | Fired when | If you cancel it… |
|:------------------|:------------------------------------------------------------------|:---------------------------------------------------|
| relevant | an element that is hidden has become relevant and will be shown | the element will remain irrelevant and stay hidden |
| irrelevant | an element that is shown has become irrelevant and will be hidden | the element will remain relevant and be visible |
| relevant-done | an element became relevant and is now shown | not applicable |
| irrelevant-done | an element became irrelevant and has been hidden | not applicable |
| Event name | Fired when | If you cancel it… |
|:-----------|:------------------------------------------------------------------|:---------------------------------------------------|
| relevant | an element that is hidden has become relevant and will be shown | the element will remain irrelevant and stay hidden |
| irrelevant | an element that is shown has become irrelevant and will be hidden | the element will remain relevant and be visible |

You can suppress the `relevant` and `irrelevant` events and cancel them to prevent an elements relevance state from changing.
You will need to cancel the event before it reaches the `document` (this is where the default handlers are bound).

The `relevant-done` and `irrelevant-done` events are fired after animations are complete and are provided as hooks in case you need to redraw the layout.
## Browser support notes

### Hiding elements when not relevant

Elements are hidden by toggling the HTML5 `hidden` attribute. Modern browsers support this element. You can provide support in older browsers by using:

```css
[hidden] {
display: none;
}
```

However, the script will check whether 'hidden' elements remain visible. If they are, it will use the jQuery `.hide()` and `.slideDown()` methods to control relevance. This results in the style `display` being changed to `none` when elements are not relevant, and provides a fallback animation.

You can override `hidden` in modern browsers to implement CSS transitions. For example:

```css
body {
line-height: 1.3;
}
li {
transition: all 0.3s ease;
}
li[hidden] {
max-height: 0;
line-height: 0;
opacity: 0;
overflow: hidden;
}
```

### Toggling relevance with `select`

Make sure your `option` elements have a `value` attribute to support older browsers. The relevance script relies on reading the `.value` property of the `select` element. Old browsers do not provide this property unless it is also specified on the `option` elements.

Use this format:

```html
<select id="colour-space" name="colourSpace">
<option value="RGB">RGB</option>
<option value="CMYK">CMYK</option>
</select>
```

This format (missing `value`) fails in old browsers:

```html
<select id="colour-space" name="colourSpace">
<option>RGB</option>
<option>CMYK</option>
</select>
```
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "relevance",
"description": "Progressive disclosure (relevance) for HTML elements",
"version": "1.2.0",
"version": "2.0.0",
"homepage": "https://github.com/bboyle/relevance",
"authors": [
"Ben Boyle <benjamins.boyle@gmail.com>"
Expand Down
67 changes: 35 additions & 32 deletions dist/relevance.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
/*! relevance - v1.6.0-beta.1 - 2015-02-24
* https://github.com/bboyle/relevance
* Copyright (c) 2015 Ben Boyle; Licensed MIT */
/*! relevance - v2.0.0 - 2015-02-27
* https://github.com/bboyle/relevance
* Copyright (c) 2015 Ben Boyle; Licensed MIT */
if ( jQuery !== 'undefined' ) {
(function( $ ) {
'use strict';

var relevantEvent = 'relevant',
irrelevantEvent = 'irrelevant',
relevantDoneEvent = 'relevant-done',
irrelevantDoneEvent = 'irrelevant-done',
elementsToDisable = 'button, input, select, textarea',
polyfillHidden = (function() {
var hidden = $( '<div hidden></div>' );
var isHidden = hidden.appendTo( 'body' ).is( ':visible' );
hidden.remove();
return ! isHidden;
}()),

formElementsByName = function( form, name ) {
// filter out the @id matching of HTMLFormElement.elements[]
Expand Down Expand Up @@ -94,17 +98,13 @@ if ( jQuery !== 'undefined' ) {
// if the element is visible, fire an "irrelevant" event
relevant: function( makeRelevant ) {
var targets;
if ( ! makeRelevant ) {
targets = this.filter( ':visible' ).trigger( irrelevantEvent );

if ( targets.length ) {
recalculateDependents.call( targets, false );
}
if ( makeRelevant ) {
targets = this.filter( '[hidden]' ).trigger( relevantEvent );
} else {
targets = this.filter( ':hidden' ).trigger( relevantEvent );
if ( targets.length ) {
recalculateDependents.call( targets );
}
targets = this.not( '[hidden]' ).trigger( irrelevantEvent );
}
if ( targets.length ) {
recalculateDependents.call( targets, makeRelevant );
}
return this;
},
Expand All @@ -123,33 +123,36 @@ if ( jQuery !== 'undefined' ) {
});

// stop animation, remove @hidden and @aria-hidden, start showing
return this.stop( true, true ).removeAttr( 'hidden' ).removeAttr( 'aria-hidden' ).slideDown(function() {
// done
$( this ).trigger( relevantDoneEvent );
});
if ( polyfillHidden ) {
this.stop( true, true ).slideDown();
}
return this.removeAttr( 'hidden' ).removeAttr( 'aria-hidden' );
},

// $( x ).relevance( 'hide' )
// hides the element (does not check if element is already hidden)
// triggers 'irrelevant-done' after hiding is complete
hide: function() {

// stop animation, start hiding
return this.stop( true, true ).hide( 0, function() {
var $this = $( this );
this.attr({
hidden: 'hidden',
'aria-hidden': 'true'
});

// disable elements (including self if appropriate)
$this.filter( elementsToDisable ).add( $this.find( elementsToDisable )).each(function() {
if ( polyfillHidden ) {
this.stop( true, true ).hide( 0, function() {
var $this = $( this );
// disable elements (including self if appropriate)
$this.filter( elementsToDisable ).add( $this.find( elementsToDisable )).each(function() {
this.setAttribute( 'disabled', 'disabled' );
});
});
} else {
this.filter( elementsToDisable ).add( this.find( elementsToDisable )).each(function() {
this.setAttribute( 'disabled', 'disabled' );
});
}

// once hidden, toggle irrelevant with @hidden and aria-hidden
this.setAttribute( 'hidden', 'hidden' );
this.setAttribute( 'aria-hidden', 'true' );

// done
$this.trigger( irrelevantDoneEvent );
});
return this;
},

// $( x ).relevance( 'relevantWhen', { name: radio/checkbox/select, value: requiredValue, negate: false | true })
Expand Down
4 changes: 2 additions & 2 deletions dist/relevance.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 3e27129

Please sign in to comment.