From 2132d292e7bbf368e1c21be10b3ddf67a1b4e496 Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Mon, 10 Feb 2014 13:36:37 -0600 Subject: [PATCH 1/5] fix(click): Clicks firing twice, closes #573 --- js/ext/angular/test/clickTests.html | 49 +++++++++++++++++------------ js/utils/poly.js | 17 ++++++++-- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/js/ext/angular/test/clickTests.html b/js/ext/angular/test/clickTests.html index 574f46cc66..5a10274f2e 100644 --- a/js/ext/angular/test/clickTests.html +++ b/js/ext/angular/test/clickTests.html @@ -112,6 +112,13 @@ +
+ + Checkbox {{ htmlCheckboxData.checkedValue }} +
+ @@ -130,6 +137,8 @@ .controller('MyCtrl', function($scope) { + $scope.htmlCheckboxData = {}; + $scope.otherTests = function() { if($scope.testBtnText == 'HTML') { $scope.testBtnText = 'AngJS'; @@ -140,18 +149,18 @@ $scope.otherTests(); $scope.htmlToggleClick = function() { - console.log('htmlToggleClick', 'click'); + console.debug('htmlToggleClick', 'click'); $scope.buttonValue = 'html' + Math.floor(Math.random() * 999); }; $scope.stringClick = 'stringMethod()'; $scope.stringMethod = function() { - console.log('toggle {{ stringClick }]', 'click'); + console.debug('toggle {{ stringClick }]', 'click'); $scope.buttonValue = 'tg' + Math.floor(Math.random() * 999); }; $scope.itemClick = function() { - console.log('itemClick()', 'click'); + console.debug('itemClick()', 'click'); $scope.buttonValue = 'itm' + Math.floor(Math.random() * 999); }; @@ -159,28 +168,28 @@ { label: 'Item 1', actionItem: function() { - console.log('item.actionItem()', 'click') + console.debug('item.actionItem()', 'click') $scope.buttonValue = 'itm' + Math.floor(Math.random() * 999); } } ]; $scope.buttonClick = function() { - console.log('button ng-click', 'click') + console.debug('button ng-click', 'click') $scope.buttonValue = 'btn' + Math.floor(Math.random() * 999); }; $scope.divClick = function() { - console.log('div ng-click', 'click') + console.debug('div ng-click', 'click') $scope.buttonValue = 'div' + Math.floor(Math.random() * 999); }; $scope.radioModel = {} $scope.radioChange = function() { - console.log('radio ng-change', 'change', $scope.radioModel.data); + console.debug('radio ng-change', 'change', $scope.radioModel.data); }; $scope.radioClick = function(val) { - console.log('radio ng-click', 'click', val); + console.debug('radio ng-click', 'click', val); $scope.buttonValue = 'rd' + Math.floor(Math.random() * 999); }; @@ -192,23 +201,23 @@ } document.getElementById('radio1').addEventListener('change', function(){ - console.log('radio 1', 'change'); + console.debug('radio 1', 'change'); }); document.getElementById('radio1').addEventListener('click', function(){ - console.log('radio 1', 'click'); + console.debug('radio 1', 'click'); }); document.getElementById('radio2').addEventListener('change', function(){ - console.log('radio 2', 'change'); + console.debug('radio 2', 'change'); }); document.getElementById('radio2').addEventListener('click', function(){ - console.log('radio 2', 'click'); + console.debug('radio 2', 'click'); }); document.addEventListener('touchstart', function(e){ - console.log('touchstart'); + console.debug('touchstart'); }); document.addEventListener('touchend', function(e){ - console.log('touchend'); + console.debug('touchend'); if(!e.changedTouches || !e.changedTouches.length) return; var dot = document.createElement('div'); @@ -223,16 +232,16 @@ }, 3000); }); document.addEventListener('mousedown', function(){ - console.log('mousedown'); + console.debug('mousedown'); }); document.addEventListener('mouseup', function(){ - console.log('mouseup'); + console.debug('mouseup'); }); // document.addEventListener('mousemove', function(event){ - // console.log('mousemove', 'clientX: ' + event.clientX, 'clientY: ' + event.clientY); + // console.debug('mousemove', 'clientX: ' + event.clientX, 'clientY: ' + event.clientY); // }); document.addEventListener('click', function(event){ - console.log('click', 'clientX: ' + event.clientX, 'clientY: ' + event.clientY); + console.debug('click', 'clientX: ' + event.clientX, 'clientY: ' + event.clientY); }); document.getElementById('clear').addEventListener('click', function(){ setTimeout(clearMsgs, 200); @@ -258,10 +267,10 @@ for (var i = 0, j = arguments.length; i < j; i++){ args.push(arguments[i]); } - console.log.apply(this, args); + console.debug.apply(this, args); }; - console.log = function() { + console.debug = function() { //return; if(stopped) return; diff --git a/js/utils/poly.js b/js/utils/poly.js index fbe74f7640..8d0b094afd 100644 --- a/js/utils/poly.js +++ b/js/utils/poly.js @@ -33,6 +33,8 @@ // simulate a normal click by running the element's click method then focus on it if(ele.disabled) return; + console.debug('tapElement', ele.tagName, ele.className); + var c = getCoordinates(e); // using initMouseEvent instead of MouseEvent for our Android friends @@ -50,7 +52,10 @@ } // remember the coordinates of this tap so if it happens again we can ignore it - recordCoordinates(e); + // but only if the coordinates are not already being actively disabled + if( !isRecentTap(e) ) { + recordCoordinates(e); + } // set the last tap time so if a click event quickly happens it knows to ignore it ele.lastTap = Date.now(); @@ -65,12 +70,14 @@ if( isRecentTap(e) ) { // if a tap in the same area just happened, don't continue + console.debug('tapPolyfill', 'isRecentTap', ele.tagName); return; } - if(e.target.lastClick && e.target.lastClick + CLICK_PREVENT_DURATION > Date.now()) { + if(ele.lastClick && ele.lastClick + CLICK_PREVENT_DURATION > Date.now()) { // if a click recently happend on this element, don't continue // (yes on some devices it's possible for a click to happen before a touchend) + console.debug('tapPolyfill', 'recent lastClick', ele.tagName); return; } @@ -111,6 +118,7 @@ if(e.target.control.labelLastTap && e.target.control.labelLastTap + CLICK_PREVENT_DURATION > Date.now()) { // Android will fire a click for the label, and a click for the input which it is associated to // this stops the second ghost click from the label from continuing + console.debug('preventGhostClick', 'labelLastTap'); e.stopPropagation(); e.preventDefault(); return false; @@ -122,12 +130,14 @@ // The input's click event will propagate so don't bother letting this label's click // propagate cuz it causes double clicks. However, do NOT e.preventDefault(), because // the label still needs to click the input + console.debug('preventGhostClick', 'label stopPropagation'); e.stopPropagation(); return; } if( isRecentTap(e) ) { // a tap has already happened at these coordinates recently, ignore this event + console.debug('preventGhostClick', 'isRecentTap', e.target.tagName); e.stopPropagation(); e.preventDefault(); return false; @@ -135,6 +145,7 @@ if(e.target.lastTap && e.target.lastTap + CLICK_PREVENT_DURATION > Date.now()) { // this element has already had the tap poly fill run on it recently, ignore this event + console.debug('preventGhostClick', 'e.target.lastTap', e.target.tagName); e.stopPropagation(); e.preventDefault(); return false; @@ -201,7 +212,7 @@ } var tapCoordinates = {}; // used to remember coordinates to ignore if they happen again quickly - var CLICK_PREVENT_DURATION = 350; // amount of milliseconds to check for ghostclicks + var CLICK_PREVENT_DURATION = 450; // amount of milliseconds to check for ghostclicks // set global click handler and check if the event should stop or not document.addEventListener('click', preventGhostClick, true); From 2e628dd8422cadf6f04665c85dd42243b080d79b Mon Sep 17 00:00:00 2001 From: Andy Joslin Date: Mon, 10 Feb 2014 14:46:38 -0500 Subject: [PATCH 2/5] chore(build): cleanup ionic.bundle.js --- Gruntfile.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index fc7c0bc494..e6fdba2f50 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -19,21 +19,18 @@ module.exports = function(grunt) { }, bundle: { options: { - banner: grunt.file.read('js/_license.js') + '\n' + + banner: '/*!\n' + ' * ionic.bundle.js is a concatenation of:\n' + - ' * angular.js,\n'+ - ' * angular-animate.js,\n'+ - ' * angular-ui-router.js,\n'+ - ' * ionic.js,\n'+ - ' * ionic-angular.js\n'+ + ' * ionic.js, angular.js, angular-animate.js,\n'+ + ' * angular-ui-router.js, and ionic-angular.js\n'+ ' */\n\n' }, src: [ + 'dist/js/ionic.js', 'config/lib/js/angular/angular.js', 'config/lib/js/angular/angular-animate.js', 'config/lib/js/angular-ui/angular-ui-router.js', - 'dist/js/ionic.js', 'dist/js/ionic-angular.js' ], dest: 'dist/js/ionic.bundle.js' @@ -43,10 +40,10 @@ module.exports = function(grunt) { banner: '<%= concat.bundle.options.banner %>' }, src: [ + 'dist/js/ionic.min.js', 'config/lib/js/angular/angular.min.js', 'config/lib/js/angular/angular-animate.min.js', 'config/lib/js/angular-ui/angular-ui-router.min.js', - 'dist/js/ionic.min.js', 'dist/js/ionic-angular.min.js' ], dest: 'dist/js/ionic.bundle.min.js' @@ -79,6 +76,7 @@ module.exports = function(grunt) { dist: { files: { 'dist/js/ionic.js': 'dist/js/ionic.js', + 'dist/js/ionic.bundle.js': 'dist/js/ionic.bundle.js', 'dist/js/ionic-angular.js': 'dist/js/ionic-angular.js' }, options: { From 8f845cc6fb27f2c29cab2eb177a7929b35da57d3 Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Mon, 10 Feb 2014 14:09:04 -0600 Subject: [PATCH 3/5] css test fixes --- test/cards.html | 16 +++++++++------- test/type.html | 4 ++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/test/cards.html b/test/cards.html index 8b8a6b6332..aa83ba1047 100644 --- a/test/cards.html +++ b/test/cards.html @@ -1,11 +1,13 @@ - + Cards - - - + + + @@ -13,7 +15,7 @@

Cards

-
+
@@ -136,9 +138,9 @@
-

Homepage

+

All CSS Tests

-
+ diff --git a/test/type.html b/test/type.html index 5d4ad295de..066a874c70 100644 --- a/test/type.html +++ b/test/type.html @@ -13,7 +13,7 @@

Type

-
+

I'm an H1 Element

I'm an H2 Element

I'm an H3 Element

@@ -23,7 +23,7 @@

I'm a paragraph Element!

As am I'm a paragraph Element too.


-

Homepage

+

All CSS Tests

From de50ada209d2e1851974d0b0b649da423341a490 Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Mon, 10 Feb 2014 14:09:44 -0600 Subject: [PATCH 4/5] add .content class for non content directive html, closes #568 --- scss/_scaffolding.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scss/_scaffolding.scss b/scss/_scaffolding.scss index 48e433b53b..763cbb9ba9 100644 --- a/scss/_scaffolding.scss +++ b/scss/_scaffolding.scss @@ -46,6 +46,11 @@ body, .ionic-body { -webkit-user-drag: none; } +.content { + // used for content areas not using the content directive + position: relative +} + .scroll-content { top: 0; right: 0; From 74a05a03388f1a9a77141f078623b018bf2829eb Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Mon, 10 Feb 2014 15:07:20 -0600 Subject: [PATCH 5/5] fix(backButton): able to hide back button if any back button attr set in navBar, closes #564 --- .../angular/src/directive/ionicViewState.js | 2 +- .../angular/test/directive/ionicView.unit.js | 32 +++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/js/ext/angular/src/directive/ionicViewState.js b/js/ext/angular/src/directive/ionicViewState.js index 45c5690d69..f358599015 100644 --- a/js/ext/angular/src/directive/ionicViewState.js +++ b/js/ext/angular/src/directive/ionicViewState.js @@ -95,7 +95,7 @@ angular.module('ionic.ui.viewState', ['ionic.service.view', 'ionic.service.gestu if(tAttrs.type) tElement.addClass(tAttrs.type); return function link($scope, $element, $attr) { - var canHaveBackButton = !(!tAttrs.backButtonType && !tAttrs.backButtonLabel); + var canHaveBackButton = !(!tAttrs.backButtonType && !tAttrs.backButtonLabel && !tAttrs.backButtonIcon); $scope.enableBackButton = canHaveBackButton; $rootScope.$on('viewState.showNavBar', function(e, showNavBar) { diff --git a/js/ext/angular/test/directive/ionicView.unit.js b/js/ext/angular/test/directive/ionicView.unit.js index 089ddde7bc..62a09d6bfb 100644 --- a/js/ext/angular/test/directive/ionicView.unit.js +++ b/js/ext/angular/test/directive/ionicView.unit.js @@ -83,13 +83,41 @@ describe('Ionic View', function() { expect(element.hasClass('bar-positive')).toEqual(true); }); - it('should not show the back button if no back button attributes set', function() { + it('should not have the back button if no back button attributes set', function() { var element = compile('')(scope); scope.$digest(); var backButton = element.find('div').find('button'); expect(backButton.length).toEqual(0); }); + it('should have the back button if back-button-type attributes set', function() { + var element = compile('')(scope); + scope.$digest(); + var backButton = element.find('div').find('button'); + expect(backButton.length).toEqual(1); + }); + + it('should have the back button if back-button-icon attributes set', function() { + var element = compile('')(scope); + scope.$digest(); + var backButton = element.find('div').find('button'); + expect(backButton.length).toEqual(1); + }); + + it('should have the back button if back-button-label attributes set', function() { + var element = compile('')(scope); + scope.$digest(); + var backButton = element.find('div').find('button'); + expect(backButton.length).toEqual(1); + }); + + it('should have the back button if all back button attributes set', function() { + var element = compile('')(scope); + scope.$digest(); + var backButton = element.find('div').find('button'); + expect(backButton.length).toEqual(1); + }); + it('should set just a back button icon, no text', function() { var element = compile('')(scope); scope.$digest(); @@ -111,7 +139,7 @@ describe('Ionic View', function() { expect(backButton.html()).toEqual('Back'); }); - it('should set a back button with an icon and text, button-clear', function() { + it('should set a back button with an icon and text, button-icon', function() { var element = compile('')(scope); scope.$digest(); var backButton = element.find('div').find('button');