ng-click fixes

This commit is contained in:
Adam Bradley
2014-01-29 11:20:38 -06:00
parent 238abd8b69
commit 4354828ce1
8 changed files with 226 additions and 59 deletions

View File

@@ -44,7 +44,8 @@ angular.module('ionic.ui', [
'ionic.ui.list',
'ionic.ui.checkbox',
'ionic.ui.toggle',
'ionic.ui.radio'
'ionic.ui.radio',
'ionic.ui.touch'
]);
@@ -2564,6 +2565,58 @@ angular.module('ionic.ui.toggle', [])
})(window.ionic);
;
// Similar to Angular's ngTouch, however it uses Ionic's tap detection
// and click simulation. ngClick
(function(angular, ionic) {'use strict';
angular.module('ionic.ui.touch', [])
.config(['$provide', function($provide) {
$provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
// drop the default ngClick directive
$delegate.shift();
return $delegate;
}]);
}])
.directive('ngClick', ['$parse', function($parse) {
function onTap(e) {
// wire this up to Ionic's tap/click simulation
ionic.clickElement(e.target, e);
}
// Actual linking function.
return function(scope, element, attr) {
var clickHandler = $parse(attr.ngClick);
element.on('click', function(event) {
scope.$apply(function() {
clickHandler(scope, {$event: (event)});
});
});
ionic.on('tap', onTap, element[0]);
// Hack for iOS Safari's benefit. It goes searching for onclick handlers and is liable to click
// something else nearby.
element.onclick = function(event) { };
scope.$on('$destroy', function () {
ionic.off('tap', onTap, element[0]);
});
};
}]);
})(window.angular, window.ionic);
;
(function() {
'use strict';

View File

File diff suppressed because one or more lines are too long

52
dist/js/ionic.js vendored
View File

@@ -1909,22 +1909,31 @@ window.ionic = {
})();
// polyfill use to simulate native "tap"
function inputTapPolyfill(ele, e) {
ionic.clickElement = function(ele, e) {
// simulate a normal click by running the element's click method then focus on it
ele.click();
ele.focus();
if(ele.disabled) return;
var c = getCoordinates(e.gesture);
var clickEvent = new MouseEvent('click', {
clientX: c.x,
clientY: c.y,
bubbles: true,
cancelable: true
});
ele.dispatchEvent(clickEvent);
if(ele.tagName === 'INPUT' || ele.tagName === 'TEXTAREA' || ele.tagName === 'SELECT') {
ele.focus();
} else {
ele.blur();
}
// remember the coordinates of this tap so if it happens again we can ignore it
recordTapCoordinates(e);
recordCoordinates(e);
// set the last tap time so if a click event quickly happens it knows to ignore it
ele.lastTap = Date.now();
// Stop! HOWEVER!! with touch devices there are still ghostclicks, hence the above logic
e.stopPropagation();
e.preventDefault();
return false;
}
};
function tapPolyfill(orgEvent) {
// if the source event wasn't from a touch event then don't use this polyfill
@@ -1951,12 +1960,12 @@ window.ionic = {
ele.tagName === "TEXTAREA" ||
ele.tagName === "SELECT" ) {
return inputTapPolyfill(ele, e);
return ionic.clickElement(ele, e);
} else if( ele.tagName === "LABEL" ) {
// check if the tapped label has an input associated to it
if(ele.control) {
return inputTapPolyfill(ele.control, e);
return ionic.clickElement(ele.control, e);
}
}
ele = ele.parentElement;
@@ -2001,7 +2010,7 @@ window.ionic = {
// remember the coordinates of this click so if a tap or click in the
// same area quickly happened again we can ignore it
recordTapCoordinates(e);
recordCoordinates(e);
}
function isRecentTap(event) {
@@ -2023,7 +2032,7 @@ window.ionic = {
}
}
function recordTapCoordinates(event) {
function recordCoordinates(event) {
var c = getCoordinates(event);
if(c.x && c.y) {
var tapId = 'ts' + Date.now();
@@ -2042,13 +2051,16 @@ window.ionic = {
function getCoordinates(event) {
// This method can get coordinates for both a mouse click
// or a touch depending on the given event
var touches = event.touches && event.touches.length ? event.touches : [event];
var e = (event.changedTouches && event.changedTouches[0]) ||
(event.originalEvent && event.originalEvent.changedTouches &&
event.originalEvent.changedTouches[0]) ||
touches[0].originalEvent || touches[0];
if(event) {
var touches = event.touches && event.touches.length ? event.touches : [event];
var e = (event.changedTouches && event.changedTouches[0]) ||
(event.originalEvent && event.originalEvent.changedTouches &&
event.originalEvent.changedTouches[0]) ||
touches[0].originalEvent || touches[0];
return { x: e.clientX, y: e.clientY }; // return the click or touch coordinates
if(e) return { x: e.clientX, y: e.clientY };
}
return { x:0, y:0 };
}
var tapCoordinates = {}; // used to remember coordinates to ignore if they happen again quickly

View File

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,51 @@
// Similar to Angular's ngTouch, however it uses Ionic's tap detection
// and click simulation. ngClick
(function(angular, ionic) {'use strict';
angular.module('ionic.ui.touch', [])
.config(['$provide', function($provide) {
$provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
// drop the default ngClick directive
$delegate.shift();
return $delegate;
}]);
}])
.directive('ngClick', ['$parse', function($parse) {
function onTap(e) {
// wire this up to Ionic's tap/click simulation
ionic.clickElement(e.target, e);
}
// Actual linking function.
return function(scope, element, attr) {
var clickHandler = $parse(attr.ngClick);
element.on('click', function(event) {
scope.$apply(function() {
clickHandler(scope, {$event: (event)});
});
});
ionic.on('tap', onTap, element[0]);
// Hack for iOS Safari's benefit. It goes searching for onclick handlers and is liable to click
// something else nearby.
element.onclick = function(event) { };
scope.$on('$destroy', function () {
ionic.off('tap', onTap, element[0]);
});
};
}]);
})(window.angular, window.ionic);

View File

@@ -31,7 +31,8 @@ angular.module('ionic.ui', [
'ionic.ui.list',
'ionic.ui.checkbox',
'ionic.ui.toggle',
'ionic.ui.radio'
'ionic.ui.radio',
'ionic.ui.touch'
]);

View File

@@ -9,27 +9,46 @@
<link rel="stylesheet" href="../../../../dist/css/ionic.css">
<script src="../../../../dist/js/ionic.js"></script>
<script src="../../../../dist/js/angular/angular.js"></script>
<script src="../../../../dist/js/angular/angular.min.js"></script>
<script src="../../../../dist/js/angular/angular-animate.min.js"></script>
<script src="../../../../dist/js/angular/angular-sanitize.min.js"></script>
<script src="../../../../dist/js/angular-ui/angular-ui-router.min.js"></script>
<script src="../../../../dist/js/ionic-angular.js"></script>
<style>
td { padding: 2px 4px }
input { margin: 10px !important; }
.item-content {
padding: 2px !important;
}
.list {
margin: 5px !important;
}
.button {
line-height: 18px !important;
min-height: 30px !important;
}
.dot {
position: absolute;
width: 3px;
height: 3px;
background-color: red;
z-index: 1000;
}
</style>
</head>
<body ng-controller="MyCtrl">
<form id="form">
<button class="button" ng-click="buttonClick()">button ng-click</button>
<div class="div button" ng-click="buttonClick()">div ng-click</div>
<button class="button" ng-click="buttonClick()">button</button>
<div class="div button" ng-click="buttonClick()">div</div>
{{ buttonValue }} -
{{ radioModel.data }}
<div class="list">
<item ng-repeat="item in menuItems" item="item" ng-click="item.actionItem()">{{item.label}}</item>
<item ng-repeat="item in menuItems" item="item" ng-click="item.actionItem()">ng-click="item.actionItem()"</item>
<item ng-click="itemClick()">ng-click="itemClick()"</item>
<item ng-click="{{ stringClick }}">ng-click="{{ stringClick }]"</item>
<radio ng-change="radioChange()"
ng-click="radioClick(radioModel.data)"
@@ -46,9 +65,7 @@
<label class="label1">
<input type="radio" name="radio" id="radio1" class="radio1">
</label>
<label class="label2">
<input type="radio" name="radio" id="radio2" class="radio2">
</label>
<input type="radio" name="radio" id="radio2" class="radio2">
<button id="clear">Clear</button>
<button id="stop">Stop</button>
@@ -61,15 +78,20 @@
.controller('MyCtrl', function($scope) {
$scope.stringClick = 'stringMethod()';
$scope.stringMethod = function() {
console.log('{{ stringClick }]', 'click')
};
$scope.itemClick = function() {
console.log('itemClick')
console.log('itemClick()', 'click')
};
$scope.menuItems = [
{
label: 'Label',
label: 'Item 1',
actionItem: function() {
console.log('actionItem')
console.log('item.actionItem()', 'click')
}
}
];
@@ -110,8 +132,20 @@
document.addEventListener('touchstart', function(e){
console.log('touchstart');
});
document.addEventListener('touchend', function(){
document.addEventListener('touchend', function(e){
console.log('touchend');
if(!e.changedTouches || !e.changedTouches.length) return;
var dot = document.createElement('div');
dot.style.left = (e.changedTouches[0].clientX - 1) + 'px';
dot.style.top = (e.changedTouches[0].clientY - 1) + 'px';
dot.className = 'dot';
dot.id = 'dot' + Date.now();
document.body.appendChild(dot);
setTimeout(function(){
var oldDot = document.getElementById(dot.id);
oldDot.parentElement.removeChild(oldDot)
}, 3000);
});
document.addEventListener('mousedown', function(){
console.log('mousedown');
@@ -165,6 +199,10 @@
msgs.unshift( msg );
if(msgs.length > 30) {
msgs.splice(30);
}
// do this so we try not to interfere with the device performance
clearTimeout(timeId);
timeId = setTimeout(function(){

View File

@@ -29,22 +29,31 @@
})();
// polyfill use to simulate native "tap"
function inputTapPolyfill(ele, e) {
ionic.clickElement = function(ele, e) {
// simulate a normal click by running the element's click method then focus on it
ele.click();
ele.focus();
if(ele.disabled) return;
var c = getCoordinates(e.gesture);
var clickEvent = new MouseEvent('click', {
clientX: c.x,
clientY: c.y,
bubbles: true,
cancelable: true
});
ele.dispatchEvent(clickEvent);
if(ele.tagName === 'INPUT' || ele.tagName === 'TEXTAREA' || ele.tagName === 'SELECT') {
ele.focus();
} else {
ele.blur();
}
// remember the coordinates of this tap so if it happens again we can ignore it
recordTapCoordinates(e);
recordCoordinates(e);
// set the last tap time so if a click event quickly happens it knows to ignore it
ele.lastTap = Date.now();
// Stop! HOWEVER!! with touch devices there are still ghostclicks, hence the above logic
e.stopPropagation();
e.preventDefault();
return false;
}
};
function tapPolyfill(orgEvent) {
// if the source event wasn't from a touch event then don't use this polyfill
@@ -71,12 +80,12 @@
ele.tagName === "TEXTAREA" ||
ele.tagName === "SELECT" ) {
return inputTapPolyfill(ele, e);
return ionic.clickElement(ele, e);
} else if( ele.tagName === "LABEL" ) {
// check if the tapped label has an input associated to it
if(ele.control) {
return inputTapPolyfill(ele.control, e);
return ionic.clickElement(ele.control, e);
}
}
ele = ele.parentElement;
@@ -121,7 +130,7 @@
// remember the coordinates of this click so if a tap or click in the
// same area quickly happened again we can ignore it
recordTapCoordinates(e);
recordCoordinates(e);
}
function isRecentTap(event) {
@@ -143,7 +152,7 @@
}
}
function recordTapCoordinates(event) {
function recordCoordinates(event) {
var c = getCoordinates(event);
if(c.x && c.y) {
var tapId = 'ts' + Date.now();
@@ -162,13 +171,16 @@
function getCoordinates(event) {
// This method can get coordinates for both a mouse click
// or a touch depending on the given event
var touches = event.touches && event.touches.length ? event.touches : [event];
var e = (event.changedTouches && event.changedTouches[0]) ||
(event.originalEvent && event.originalEvent.changedTouches &&
event.originalEvent.changedTouches[0]) ||
touches[0].originalEvent || touches[0];
if(event) {
var touches = event.touches && event.touches.length ? event.touches : [event];
var e = (event.changedTouches && event.changedTouches[0]) ||
(event.originalEvent && event.originalEvent.changedTouches &&
event.originalEvent.changedTouches[0]) ||
touches[0].originalEvent || touches[0];
return { x: e.clientX, y: e.clientY }; // return the click or touch coordinates
if(e) return { x: e.clientX, y: e.clientY };
}
return { x:0, y:0 };
}
var tapCoordinates = {}; // used to remember coordinates to ignore if they happen again quickly