Bug Fix: Touch support for menu

Support for PointerEvents, MSPointerEvents and Touch with fallback to
Mouse events.
This commit is contained in:
Gary Sharp
2013-11-20 15:06:37 +11:00
parent eabd9671f0
commit e4c86f1cc1
4 changed files with 180 additions and 229 deletions
+87 -146
View File
@@ -39567,174 +39567,115 @@ jQuery.fn.DataTable.defaults.aLengthMenu = [[10, 20, 50, -1], [10, 20, 50, "All"
var $menu = $('#menu'); var $menu = $('#menu');
if ($menu.length > 0) { if ($menu.length > 0) {
if (Modernizr.touch) {
// Touch Events function subMenuShow() {
$menu var $this = $(this);
.on('mouseover', 'li.hasSubMenu', function (e) { var $subMenu = $this.children('ul.subMenu');
var $this = $(this); var hideToken = $this.data('menuHideToken');
var $subMenu = $this.children('ul.subMenu');
var hideToken = $this.data('menuHideToken'); if (hideToken)
if (hideToken) window.clearTimeout(hideToken);
window.clearTimeout(hideToken);
if (!$subMenu.is(':visible')) if (!$subMenu.is(':visible'))
$subMenu.show(); $subMenu.show();
}) }
.on('mouseout', 'li.hasSubMenu', function (e) { function subMenuHide() {
var $this = $(this); var $this = $(this);
var $subMenu = $this.children('ul.subMenu'); var $subMenu = $this.children('ul.subMenu');
var hideToken = window.setTimeout(function () {
$subMenu.hide(); var hideToken = window.setTimeout(function () {
}, 250); $subMenu.hide();
$this.data('menuHideToken', hideToken); }, 250);
})
.on('touchstart', 'li.hasSubMenu', function (e) { $this.data('menuHideToken', hideToken);
var $this = $(this); }
var $link = $this.children('a'); function subMenuTouchDown(e, preventClick) {
var $subMenu = $this.children('ul.subMenu'); var $this = $(this);
if (!$subMenu.is(':visible')) { var $link = $this.children('a');
$subMenu.show(); var $subMenu = $this.children('ul.subMenu');
e.preventDefault();
e.stopPropagation(); if (!$subMenu.is(':visible')) {
return false;
$subMenu.show();
e.preventDefault();
e.stopPropagation();
if (preventClick) {
// Stop Click Event
if ($link.length > 0) {
var preventClick = function () { $link.off('click', preventClick); return false; }
$link.on('click', preventClick);
} }
}); }
} else if (Modernizr.testProp('pointerEvents')) {
return false;
}
}
if (Modernizr.hasEvent('pointerdown')) {
// Pointer Events // Pointer Events
$menu $menu
.on('pointerover', 'li.hasSubMenu', function (e) { .on('pointerover', 'li.hasSubMenu', function (e) {
if (e.originalEvent.pointerType != 'touch') { if (e.originalEvent.pointerType !== 'touch') {
var $this = $(this); subMenuShow.call(this);
var $subMenu = $this.children('ul.subMenu');
var hideToken = $this.data('menuHideToken');
if (hideToken)
window.clearTimeout(hideToken);
if (!$subMenu.is(':visible'))
$subMenu.show();
} }
}) })
.on('pointerout', 'li.hasSubMenu', function (e) { .on('pointerout', 'li.hasSubMenu', function (e) {
if (e.originalEvent.pointerType != 'touch') { if (e.originalEvent.pointerType !== 'touch') {
var $this = $(this); subMenuHide.call(this);
var $subMenu = $this.children('ul.subMenu');
var hideToken = window.setTimeout(function () {
$subMenu.hide();
}, 250);
$this.data('menuHideToken', hideToken);
} }
}) })
.on('pointerdown', 'li.hasSubMenu', function (e) { .on('pointerdown', 'li.hasSubMenu', function (e) {
if (e.originalEvent.pointerType == 'touch') { if (e.originalEvent.pointerType === 'touch') {
var $this = $(this); return subMenuTouchDown.call(this, e, true);
var $link = $this.children('a');
var $subMenu = $this.children('ul.subMenu');
if (!$subMenu.is(':visible')) {
$subMenu.show();
e.preventDefault();
e.stopPropagation();
// Stop Click Event
if ($link.length > 0) {
var preventClick = function () { $link.off('click', preventClick); return false; }
$link.on('click', preventClick);
}
return false;
}
} }
}); });
$(document).on('pointerdown', function (e) { $(document).on('pointerdown', function (e) {
if (e.originalEvent.pointerType == 'touch') { if (e.originalEvent.pointerType === 'touch') {
if ($(e.target).closest('#menu').length == 0) if ($(e.target).closest('#menu').length == 0)
$menu.find('li.hasSubMenu>ul.subMenu:visible').hide(); $menu.find('li.hasSubMenu>ul.subMenu:visible').hide();
} }
}); });
} else if (Modernizr.hasEvent('mspointerdown')) {
// MS Pointer Events
$menu
.on('MSPointerOver', 'li.hasSubMenu', function (e) {
if (e.originalEvent.pointerType !== e.originalEvent.MSPOINTER_TYPE_TOUCH) {
subMenuShow.call(this);
}
})
.on('MSPointerOut', 'li.hasSubMenu', function (e) {
if (e.originalEvent.pointerType !== e.originalEvent.MSPOINTER_TYPE_TOUCH) {
subMenuHide.call(this);
}
})
.on('MSPointerDown', 'li.hasSubMenu', function (e) {
if (e.originalEvent.pointerType === e.originalEvent.MSPOINTER_TYPE_TOUCH) {
return subMenuTouchDown.call(this, e, true);
}
});
$(document).on('MSPointerDown', function (e) {
if (e.originalEvent.pointerType === e.originalEvent.MSPOINTER_TYPE_TOUCH) {
if ($(e.target).closest('#menu').length == 0)
$menu.find('li.hasSubMenu>ul.subMenu:visible').hide();
}
});
} else if (Modernizr.touch) {
// Touch Events
$menu
.on('mouseover', 'li.hasSubMenu', subMenuShow)
.on('mouseout', 'li.hasSubMenu', subMenuHide)
.on('touchstart', 'li.hasSubMenu', function (e) {
return subMenuTouchDown.call(this, e, false);
});
} else { } else {
// Mouse Events // Mouse Events
$menu $menu
.on('mouseover', 'li.hasSubMenu', function () { .on('mouseover', 'li.hasSubMenu', subMenuShow)
var $this = $(this); .on('mouseout', 'li.hasSubMenu', subMenuHide);
var $subMenu = $this.children('ul.subMenu');
var hideToken = $this.data('menuHideToken');
if (hideToken)
window.clearTimeout(hideToken);
if (!$subMenu.is(':visible'))
$subMenu.show();
})
.on('mouseout', 'li.hasSubMenu', function () {
var $this = $(this);
var $subMenu = $this.children('ul.subMenu');
var hideToken = window.setTimeout(function () {
$subMenu.hide();
}, 250);
$this.data('menuHideToken', hideToken);
});
} }
} }
//var $menuItems = $menu.find('li');
//var $menuItemParents = $menuItems.filter('.hasSubMenu');
//var $menuSubMenus = $menuItems.filter('.subMenu');
//var menuAllowTouchNavigation = null;
//$menuItemParents.each(function () {
// var $parent = $(this);
// var $subMenu = $parent.children('ul.subMenu');
// $parent.data('menuSubMenu', $subMenu);
//}).mouseover(function () {
// var $parent = $(this);
// var $subMenu = $parent.data('menuSubMenu');
// var hideToken = $parent.data('menuHideToken');
// if (hideToken)
// window.clearTimeout(hideToken);
// if (!$subMenu.is(':visible')) {
// $subMenu.show();
// if (menuAllowTouchNavigation !== null)
// menuTouchPreventNavigation();
// }
//}).mouseout(function () {
// var $parent = $(this);
// var $subMenu = $parent.data('menuSubMenu');
// var hideToken = window.setTimeout(function () {
// $subMenu.hide();
// }, 250);
// $parent.data('menuHideToken', hideToken);
//});
//if (Modernizr.touch) {
// menuAllowTouchNavigation = true;
// $menuItemParents.children('a').on('touchstart', menuTouchStarted);
//} else if (window.navigator.msPointerEnabled) {
// menuAllowTouchNavigation = true;
// $menuItemParents.children('a').on('MSPointerUp', menuTouchMSPointerUp);
//}
//function menuTouchPreventNavigation() {
// // Block Touch Navigation for 350ms
// allowTouchNavigation = false;
// window.setTimeout(function () {
// allowTouchNavigation = true;
// }, 350);
//}
//function menuTouchNavigationBlockClick(e) {
// $(this).off('click', menuTouchNavigationBlockClick);
// e.preventDefault();
//}
////#region TouchEvents Implementation
//function menuSubMenuVisible($element) {
// return $element.closest('li').data('menuSubMenu').is(':visible');
//}
//function menuTouchStarted(e) {
// var $this = $(this);
// if (!menuSubMenuVisible($this))
// $this.click(menuTouchNavigationBlockClick);
//}
////#endregion
////#region MS Pointer Implementation
//function menuTouchMSPointerUp(e) {
// if (!allowTouchNavigation && e.originalEvent.pointerType == e.originalEvent.MSPOINTER_TYPE_TOUCH)
// $(this).click(menuTouchNavigationBlockClick);
//}
////#endregion
}); });
})(jQuery, window, document, Modernizr); })(jQuery, window, document, Modernizr);
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -17,105 +17,113 @@
var $menu = $('#menu'); var $menu = $('#menu');
if ($menu.length > 0) { if ($menu.length > 0) {
if (Modernizr.touch) {
// Touch Events function subMenuShow() {
$menu var $this = $(this);
.on('mouseover', 'li.hasSubMenu', function (e) { var $subMenu = $this.children('ul.subMenu');
var $this = $(this); var hideToken = $this.data('menuHideToken');
var $subMenu = $this.children('ul.subMenu');
var hideToken = $this.data('menuHideToken'); if (hideToken)
if (hideToken) window.clearTimeout(hideToken);
window.clearTimeout(hideToken);
if (!$subMenu.is(':visible')) if (!$subMenu.is(':visible'))
$subMenu.show(); $subMenu.show();
}) }
.on('mouseout', 'li.hasSubMenu', function (e) { function subMenuHide() {
var $this = $(this); var $this = $(this);
var $subMenu = $this.children('ul.subMenu'); var $subMenu = $this.children('ul.subMenu');
var hideToken = window.setTimeout(function () {
$subMenu.hide(); var hideToken = window.setTimeout(function () {
}, 250); $subMenu.hide();
$this.data('menuHideToken', hideToken); }, 250);
})
.on('touchstart', 'li.hasSubMenu', function (e) { $this.data('menuHideToken', hideToken);
var $this = $(this); }
var $link = $this.children('a'); function subMenuTouchDown(e, preventClick) {
var $subMenu = $this.children('ul.subMenu'); var $this = $(this);
if (!$subMenu.is(':visible')) { var $link = $this.children('a');
$subMenu.show(); var $subMenu = $this.children('ul.subMenu');
e.preventDefault();
e.stopPropagation(); if (!$subMenu.is(':visible')) {
return false;
$subMenu.show();
e.preventDefault();
e.stopPropagation();
if (preventClick) {
// Stop Click Event
if ($link.length > 0) {
var preventClick = function () { $link.off('click', preventClick); return false; }
$link.on('click', preventClick);
} }
}); }
} else if (Modernizr.testProp('pointerEvents')) {
return false;
}
}
if (Modernizr.hasEvent('pointerdown')) {
// Pointer Events // Pointer Events
$menu $menu
.on('pointerover', 'li.hasSubMenu', function (e) { .on('pointerover', 'li.hasSubMenu', function (e) {
if (e.originalEvent.pointerType != 'touch') { if (e.originalEvent.pointerType !== 'touch') {
var $this = $(this); subMenuShow.call(this);
var $subMenu = $this.children('ul.subMenu');
var hideToken = $this.data('menuHideToken');
if (hideToken)
window.clearTimeout(hideToken);
if (!$subMenu.is(':visible'))
$subMenu.show();
} }
}) })
.on('pointerout', 'li.hasSubMenu', function (e) { .on('pointerout', 'li.hasSubMenu', function (e) {
if (e.originalEvent.pointerType != 'touch') { if (e.originalEvent.pointerType !== 'touch') {
var $this = $(this); subMenuHide.call(this);
var $subMenu = $this.children('ul.subMenu');
var hideToken = window.setTimeout(function () {
$subMenu.hide();
}, 250);
$this.data('menuHideToken', hideToken);
} }
}) })
.on('pointerdown', 'li.hasSubMenu', function (e) { .on('pointerdown', 'li.hasSubMenu', function (e) {
if (e.originalEvent.pointerType == 'touch') { if (e.originalEvent.pointerType === 'touch') {
var $this = $(this); return subMenuTouchDown.call(this, e, true);
var $link = $this.children('a');
var $subMenu = $this.children('ul.subMenu');
if (!$subMenu.is(':visible')) {
$subMenu.show();
e.preventDefault();
e.stopPropagation();
// Stop Click Event
if ($link.length > 0) {
var preventClick = function () { $link.off('click', preventClick); return false; }
$link.on('click', preventClick);
}
return false;
}
} }
}); });
$(document).on('pointerdown', function (e) { $(document).on('pointerdown', function (e) {
if (e.originalEvent.pointerType == 'touch') { if (e.originalEvent.pointerType === 'touch') {
if ($(e.target).closest('#menu').length == 0) if ($(e.target).closest('#menu').length == 0)
$menu.find('li.hasSubMenu>ul.subMenu:visible').hide(); $menu.find('li.hasSubMenu>ul.subMenu:visible').hide();
} }
}); });
} else if (Modernizr.hasEvent('mspointerdown')) {
// MS Pointer Events
$menu
.on('MSPointerOver', 'li.hasSubMenu', function (e) {
if (e.originalEvent.pointerType !== e.originalEvent.MSPOINTER_TYPE_TOUCH) {
subMenuShow.call(this);
}
})
.on('MSPointerOut', 'li.hasSubMenu', function (e) {
if (e.originalEvent.pointerType !== e.originalEvent.MSPOINTER_TYPE_TOUCH) {
subMenuHide.call(this);
}
})
.on('MSPointerDown', 'li.hasSubMenu', function (e) {
if (e.originalEvent.pointerType === e.originalEvent.MSPOINTER_TYPE_TOUCH) {
return subMenuTouchDown.call(this, e, true);
}
});
$(document).on('MSPointerDown', function (e) {
if (e.originalEvent.pointerType === e.originalEvent.MSPOINTER_TYPE_TOUCH) {
if ($(e.target).closest('#menu').length == 0)
$menu.find('li.hasSubMenu>ul.subMenu:visible').hide();
}
});
} else if (Modernizr.touch) {
// Touch Events
$menu
.on('mouseover', 'li.hasSubMenu', subMenuShow)
.on('mouseout', 'li.hasSubMenu', subMenuHide)
.on('touchstart', 'li.hasSubMenu', function (e) {
return subMenuTouchDown.call(this, e, false);
});
} else { } else {
// Mouse Events // Mouse Events
$menu $menu
.on('mouseover', 'li.hasSubMenu', function () { .on('mouseover', 'li.hasSubMenu', subMenuShow)
var $this = $(this); .on('mouseout', 'li.hasSubMenu', subMenuHide);
var $subMenu = $this.children('ul.subMenu');
var hideToken = $this.data('menuHideToken');
if (hideToken)
window.clearTimeout(hideToken);
if (!$subMenu.is(':visible'))
$subMenu.show();
})
.on('mouseout', 'li.hasSubMenu', function () {
var $this = $(this);
var $subMenu = $this.children('ul.subMenu');
var hideToken = window.setTimeout(function () {
$subMenu.hide();
}, 250);
$this.data('menuHideToken', hideToken);
});
} }
} }