Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Commit

Permalink
feat(gestures): add built in gesture system, remove HammerJS
Browse files Browse the repository at this point in the history
  • Loading branch information
ajoslin committed Jan 26, 2015
1 parent 1d5ef95 commit 8364fb5
Show file tree
Hide file tree
Showing 42 changed files with 1,358 additions and 824 deletions.
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ branches:
- master

before_script:
- export DISPLAY=:99.0 # firefox virtual screen
- sh -e /etc/init.d/xvfb start # firefox virtual screen
- npm install -g bower
- bower install
- git config --global user.email "ngmaterial@googlegroups.com"
- git config --global user.name "ngMaterial Bot"

script:
- gulp karma --browsers=PhantomJS
- gulp karma --browsers=Firefox
- ./scripts/travis-build-init.sh --sha=$TRAVIS_COMMIT

notifications:
Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ when using online tools such as [CodePen](http://codepen.io/), [Plunkr](http://p
<body>

<!-- Angular Material Dependencies -->
<script src="//cdn.jsdelivr.net/hammerjs/2.0.4/hammer.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular-animate.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular-aria.min.js"></script>
Expand All @@ -149,7 +148,6 @@ pull directly from the distribution GitHub
<body>

<!-- Angular Material Dependencies -->
<script src="//cdn.jsdelivr.net/hammerjs/2.0.4/hammer.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular-animate.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular-aria.js"></script>
Expand Down
3 changes: 1 addition & 2 deletions bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
"dependencies": {
"angular": "1.3.x",
"angular-animate": "1.3.x",
"angular-aria": "1.3.x",
"hammerjs": "~2.0.2"
"angular-aria": "1.3.x"
},
"devDependencies": {
"angular": "1.3.x",
Expand Down
2 changes: 1 addition & 1 deletion config/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ module.exports = function(config) {
'bower_components/angular-animate/angular-animate.js',
'bower_components/angular-aria/angular-aria.js',
'bower_components/angular-mocks/angular-mocks.js',
'bower_components/hammerjs/hammer.js'
'config/test-utils.js'
].concat(testSrc),

port: 9876,
Expand Down
45 changes: 29 additions & 16 deletions config/test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,25 @@ var TestUtil = {
});
},

};

beforeEach(function() {

/**
* Create a fake version of $$rAF that does things asynchronously
* Create a fake version of $$rAF that does things synchronously
*/
mockRaf: function() {
module('ng', function($provide) {
$provide.value('$$rAF', mockRaf);
module('ng', function($provide) {
$provide.value('$$rAF', mockRaf);

function mockRaf(cb) {
cb();
}
mockRaf.debounce = function(cb) {
return function() {
cb.apply(this, arguments);
};
function mockRaf(cb) {
cb();
}
mockRaf.throttle = function(cb) {
return function() {
cb.apply(this, arguments);
};
});
}
};

beforeEach(function() {
};
});

module('material.core.theming', function($mdThemingProvider) {
// Create a test version of every default palette, using a copy of the below palette.
Expand Down Expand Up @@ -85,6 +84,20 @@ beforeEach(function() {
(typeof this.actual) + (this.isNot ? ' not ' : '') + " to have type '" + type + "'.";
};
return typeof this.actual == type;
},

toHaveFields: function(fields) {
this.message = function() {
return "Expected " + angular.mock.dump(this.actual) + (this.isNot ? ' not ' : ' ') +
"to have fields matching " + angular.mock.dump(fields);
};
for (var key in fields) {
if (!(this.actual || {}).hasOwnProperty(key) ||
!angular.equals(this.actual[key], fields[key])) {
return false;
}
}
return true;
}
});

Expand Down
1 change: 0 additions & 1 deletion docs/app/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ function(COMPONENTS, DEMOS, PAGES, $routeProvider, $mdThemingProvider) {
}
});


$mdThemingProvider.theme('docs-dark', 'default')
.dark();

Expand Down
3 changes: 1 addition & 2 deletions docs/config/template/demo-index.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
<script src="/bower_components/angular-animate/angular-animate.js"></script>
<script src="/bower_components/angular-messages/angular-messages.js"></script>
<script src="/bower_components/angular-aria/angular-aria.js"></script>
<script src="/bower_components/hammerjs/hammer.js"></script>
<script src="/dist/angular-material.js"></script>

<link rel="stylesheet" href="/dist/angular-material.css">
Expand All @@ -21,7 +20,7 @@
<% }); %>
</head>

<body style="padding: 50px;">
<body>
<%= index.contents %>
</body>
</html>
2 changes: 1 addition & 1 deletion docs/config/template/index.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ <h1 class="md-toolbar-tools">
</h1>
</md-toolbar>

<md-content flex style="overflow: auto;">
<md-content flex>
<div ng-repeat="section in menu.sections">

<button class="menu-item menu-title md-menu-item"
Expand Down
3 changes: 1 addition & 2 deletions docs/gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,8 @@ module.exports = function(gulp, IS_RELEASE_BUILD) {
gulp.task('docs-js', ['docs-app', 'docs-html2js', 'demos', 'build'], function() {
return gulp.src([
'bower_components/angularytics/dist/angularytics.js',
'bower_components/hammerjs/hammer.js',
'dist/angular-material.js',
'dist/docs/js/**/*.js',
'dist/docs/js/**/*.js'
])
.pipe(concat('docs.js'))
.pipe(gulpif(IS_RELEASE_BUILD, uglify()))
Expand Down
113 changes: 32 additions & 81 deletions src/components/bottomSheet/bottomSheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,17 @@ function MdBottomSheetDirective() {
*/

function MdBottomSheetProvider($$interimElementProvider) {
// how fast we need to flick down to close the sheet, pixels/ms
var CLOSING_VELOCITY = 0.5;
var PADDING = 80; // same as css

return $$interimElementProvider('$mdBottomSheet')
.setDefaults({
options: bottomSheetDefaults
});

/* @ngInject */
function bottomSheetDefaults($animate, $mdConstant, $timeout, $$rAF, $compile, $mdTheming, $mdBottomSheet, $rootElement) {
function bottomSheetDefaults($animate, $mdConstant, $timeout, $$rAF, $compile, $mdTheming, $mdBottomSheet, $rootElement, $rootScope, $mdGesture) {
var backdrop;

return {
Expand All @@ -132,15 +135,15 @@ function MdBottomSheetProvider($$interimElementProvider) {
function onShow(scope, element, options) {
// Add a backdrop that will close on click
backdrop = $compile('<md-backdrop class="md-opaque md-bottom-sheet-backdrop">')(scope);
backdrop.on('click touchstart', function() {
backdrop.on('click', function() {
$timeout($mdBottomSheet.cancel);
});

$mdTheming.inherit(backdrop, options.parent);

$animate.enter(backdrop, options.parent, null);

var bottomSheet = new BottomSheet(element);
var bottomSheet = new BottomSheet(element, options.parent);
options.bottomSheet = bottomSheet;

// Give up focus on calling item
Expand Down Expand Up @@ -182,99 +185,47 @@ function MdBottomSheetProvider($$interimElementProvider) {
/**
* BottomSheet class to apply bottom-sheet behavior to an element
*/
function BottomSheet(element) {
var MAX_OFFSET = 80; // amount past the bottom of the element that we can drag down, this is same as in _bottomSheet.scss
var WIGGLE_AMOUNT = 20; // point where it starts to get "harder" to drag
var CLOSING_VELOCITY = 10; // how fast we need to flick down to close the sheet
var startY, lastY, velocity, transitionDelay, startTarget;

// coercion incase $mdCompiler returns multiple elements
element = element.eq(0);

element.on('touchstart', onTouchStart)
.on('touchmove', onTouchMove)
.on('touchend', onTouchEnd);
function BottomSheet(element, parent) {
var deregister = $mdGesture.register(parent, 'drag', { horizontal: false });
parent.on('$md.dragstart', onDragStart)
.on('$md.drag', onDrag)
.on('$md.dragend', onDragEnd);

return {
element: element,
cleanup: function cleanup() {
element.off('touchstart', onTouchStart)
.off('touchmove', onTouchMove)
.off('touchend', onTouchEnd);
deregister();
parent.off('$md.dragstart', onDragStart)
.off('$md.drag', onDrag)
.off('$md.dragend', onDragEnd);
}
};

function onTouchStart(e) {
e.preventDefault();
startTarget = e.target;
startY = getY(e);

function onDragStart(ev) {
// Disable transitions on transform so that it feels fast
transitionDelay = element.css($mdConstant.CSS.TRANSITION_DURATION);
element.css($mdConstant.CSS.TRANSITION_DURATION, '0s');
element.css($mdConstant.CSS.TRANSITION_DURATION, '0ms');
}

function onTouchEnd(e) {
// Re-enable the transitions on transforms
element.css($mdConstant.CSS.TRANSITION_DURATION, transitionDelay);

var currentY = getY(e);
// If we didn't scroll much, and we didn't change targets, assume its a click
if ( Math.abs(currentY - startY) < 5 && e.target == startTarget) {
angular.element(e.target).triggerHandler('click');
} else {
// If they went fast enough, trigger a close.
if (velocity > CLOSING_VELOCITY) {
$timeout($mdBottomSheet.cancel);

// Otherwise, untransform so that we go back to our normal position
} else {
setTransformY(undefined);
}
function onDrag(ev) {
var transform = ev.pointer.distanceY;
if (transform < 5) {
// Slow down drag when trying to drag up, and stop after PADDING
transform = Math.max(-PADDING, transform / 2);
}
element.css($mdConstant.CSS.TRANSFORM, 'translate3d(0,' + (PADDING + transform) + 'px,0)');
}

function onTouchMove(e) {
var currentY = getY(e);
var delta = currentY - startY;

velocity = currentY - lastY;
lastY = currentY;

// Do some conversion on delta to get a friction-like effect
delta = adjustedDelta(delta);
setTransformY(delta + MAX_OFFSET);
}

/**
* Helper function to find the Y aspect of various touch events.
**/
function getY(e) {
var touch = e.touches && e.touches.length ? e.touches[0] : e.changedTouches[0];
return touch.clientY;
}

/**
* Transform the element along the y-axis
**/
function setTransformY(amt) {
if (amt === null || amt === undefined) {
element.css($mdConstant.CSS.TRANSFORM, '');
function onDragEnd(ev) {
if (ev.pointer.distanceY > 0 &&
(ev.pointer.distanceY > 20 || Math.abs(ev.pointer.velocityY) > CLOSING_VELOCITY)) {
var distanceRemaining = element.prop('offsetHeight') - ev.pointer.distanceY;
var transitionDuration = Math.min(distanceRemaining / ev.pointer.velocityY * 0.75, 500);
element.css($mdConstant.CSS.TRANSITION_DURATION, transitionDuration + 'ms');
$timeout($mdBottomSheet.cancel);
} else {
element.css($mdConstant.CSS.TRANSFORM, 'translate3d(0, ' + amt + 'px, 0)');
}
}

// Returns a new value for delta that will never exceed MAX_OFFSET_AMOUNT
// Will get harder to exceed it as you get closer to it
function adjustedDelta(delta) {
if ( delta < 0 && delta < -MAX_OFFSET + WIGGLE_AMOUNT) {
delta = -delta;
var base = MAX_OFFSET - WIGGLE_AMOUNT;
delta = Math.max(-MAX_OFFSET, -Math.min(MAX_OFFSET - 5, base + ( WIGGLE_AMOUNT * (delta - base)) / MAX_OFFSET) - delta / 50);
element.css($mdConstant.CSS.TRANSITION_DURATION, '');
element.css($mdConstant.CSS.TRANSFORM, '');
}

return delta;
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/components/button/button.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
describe('md-button', function() {

beforeEach(TestUtil.mockRaf);
beforeEach(module('material.components.button'));

it('should convert attributes on an md-button to attributes on the generated button', inject(function($compile, $rootScope) {
Expand All @@ -12,8 +11,8 @@ describe('md-button', function() {

it('should only have one ripple container when a custom ripple color is set', inject(function ($compile, $rootScope, $timeout) {
var button = $compile('<md-button md-ink-ripple="#f00">button</md-button>')($rootScope);
var scope = button.eq(0).scope();
scope._onInput({ isFirst: true, eventType: Hammer.INPUT_START, center: { x: 0, y: 0 } });

button.triggerHandler({ type: '$md.pressdown', pointer: { x: 0, y: 0 } });
expect(button[0].getElementsByClassName('md-ripple-container').length).toBe(1);
}));

Expand Down
8 changes: 2 additions & 6 deletions src/components/checkbox/checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,8 @@ function MdCheckboxDirective(inputDirective, $mdInkRipple, $mdAria, $mdConstant,
0: {}
}, attr, [ngModelCtrl]);

// Used by switch. in Switch, we don't want click listeners; we have more granular
// touchup/touchdown listening.
if (!attr.mdNoClick) {
element.on('click', listener);
}
element.on('keypress', keypressHandler);
element.on('click', listener)
.on('keypress', keypressHandler);
ngModelCtrl.$render = render;

function keypressHandler(ev) {
Expand Down
1 change: 0 additions & 1 deletion src/components/checkbox/checkbox.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ describe('mdCheckbox', function() {

beforeEach(module('material.components.checkbox'));
beforeEach(module('ngAria'));
beforeEach(TestUtil.mockRaf);

it('should warn developers they need a label', inject(function($compile, $rootScope, $log){
spyOn($log, "warn");
Expand Down
Loading

0 comments on commit 8364fb5

Please sign in to comment.