Browse Source

Improve hover experience with hoverIntent.

pull/119/head
Evan Theurer 12 years ago
parent
commit
ba94188d85
  1. 9
      src/styles/components/_buddycondensed.scss
  2. 36
      static/js/directives/buddycondensed.js
  3. 115
      static/js/libs/jquery/jquery.hoverIntent.js
  4. 5
      static/js/main.js
  5. 2
      static/partials/buddycondensed.html

9
src/styles/components/_buddycondensed.scss

@ -42,17 +42,14 @@
display: none; display: none;
position: fixed; position: fixed;
top: 49px; top: 49px;
&:hover {
display: block;
}
} }
.desc { .desc {
display: inline-block; display: none;
font-weight: bold; font-weight: bold;
padding-left: 10px; padding-left: 10px;
cursor: default; cursor: default;
&:hover ~ .overDefaultDisplayNum { &.overNum {
display: block; display: inline-block;
} }
} }
.actions { .actions {

36
static/js/directives/buddycondensed.js

@ -18,7 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
define(['angular', 'text!partials/buddycondensed.html'], function(angular, template) { define(['angular', 'jquery', 'text!partials/buddycondensed.html', 'hoverIntent'], function(angular, $, template) {
// buddycondensed // buddycondensed
return [function() { return [function() {
@ -58,6 +58,7 @@ define(['angular', 'text!partials/buddycondensed.html'], function(angular, templ
}; };
var joined = function(buddy) { var joined = function(buddy) {
buddycondensed.push(buddy); buddycondensed.push(buddy);
buddycondensed.push(angular.extend({}, buddy));
}; };
var left = function(id) { var left = function(id) {
for (var i in buddycondensed) { for (var i in buddycondensed) {
@ -135,7 +136,38 @@ define(['angular', 'text!partials/buddycondensed.html'], function(angular, templ
}); });
}]; }];
var link = function($scope, elem, attrs, ctrl) {}; var link = function($scope, elem, attrs, ctrl) {
var overDefaultDisplayNum = elem.find(".overDefaultDisplayNum");
var desc = elem.find(".desc");
var aboveElem1 = false;
var aboveElem2 = false;
var out = function(event) {
console.log('out', event.currentTarget.className);
if (event.currentTarget === desc.get(0)) {
aboveElem1 = false;
} else if (event.currentTarget === overDefaultDisplayNum.get(0)) {
aboveElem2 = false;
}
if(!aboveElem1 && !aboveElem2) {
overDefaultDisplayNum.hide();
}
};
var over = function(event) {
console.log('out', event.currentTarget.className);
if (event.currentTarget === desc.get(0)) {
aboveElem1 = true;
} else if (event.currentTarget === overDefaultDisplayNum.get(0)) {
aboveElem2 = true;
}
overDefaultDisplayNum.show();
};
elem.hoverIntent({
over: over,
out: out,
timeout: 1000,
selector: '.desc, .overDefaultDisplayNum'
});
};
return { return {
restrict: 'E', restrict: 'E',

115
static/js/libs/jquery/jquery.hoverIntent.js

@ -0,0 +1,115 @@
/*!
* hoverIntent v1.8.1 // 2014.08.11 // jQuery v1.9.1+
* http://cherne.net/brian/resources/jquery.hoverIntent.html
*
* You may use hoverIntent under the terms of the MIT license. Basically that
* means you are free to use hoverIntent as long as this header is left intact.
* Copyright 2007, 2014 Brian Cherne
*/
/* hoverIntent is similar to jQuery's built-in "hover" method except that
* instead of firing the handlerIn function immediately, hoverIntent checks
* to see if the user's mouse has slowed down (beneath the sensitivity
* threshold) before firing the event. The handlerOut function is only
* called after a matching handlerIn.
*
* // basic usage ... just like .hover()
* .hoverIntent( handlerIn, handlerOut )
* .hoverIntent( handlerInOut )
*
* // basic usage ... with event delegation!
* .hoverIntent( handlerIn, handlerOut, selector )
* .hoverIntent( handlerInOut, selector )
*
* // using a basic configuration object
* .hoverIntent( config )
*
* @param handlerIn function OR configuration object
* @param handlerOut function OR selector for delegation OR undefined
* @param selector selector OR undefined
* @author Brian Cherne <brian(at)cherne(dot)net>
*/
(function($) {
$.fn.hoverIntent = function(handlerIn,handlerOut,selector) {
// default configuration values
var cfg = {
interval: 100,
sensitivity: 6,
timeout: 0
};
if ( typeof handlerIn === "object" ) {
cfg = $.extend(cfg, handlerIn );
} else if ($.isFunction(handlerOut)) {
cfg = $.extend(cfg, { over: handlerIn, out: handlerOut, selector: selector } );
} else {
cfg = $.extend(cfg, { over: handlerIn, out: handlerIn, selector: handlerOut } );
}
// instantiate variables
// cX, cY = current X and Y position of mouse, updated by mousemove event
// pX, pY = previous X and Y position of mouse, set by mouseover and polling interval
var cX, cY, pX, pY;
// A private function for getting mouse position
var track = function(ev) {
cX = ev.pageX;
cY = ev.pageY;
};
// A private function for comparing current and previous mouse position
var compare = function(ev,ob) {
ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
// compare mouse positions to see if they've crossed the threshold
if ( Math.sqrt( (pX-cX)*(pX-cX) + (pY-cY)*(pY-cY) ) < cfg.sensitivity ) {
$(ob).off("mousemove.hoverIntent",track);
// set hoverIntent state to true (so mouseOut can be called)
ob.hoverIntent_s = true;
return cfg.over.apply(ob,[ev]);
} else {
// set previous coordinates for next time
pX = cX; pY = cY;
// use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs)
ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval );
}
};
// A private function for delaying the mouseOut function
var delay = function(ev,ob) {
ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
ob.hoverIntent_s = false;
return cfg.out.apply(ob,[ev]);
};
// A private function for handling mouse 'hovering'
var handleHover = function(e) {
// copy objects to be passed into t (required for event object to be passed in IE)
var ev = $.extend({},e);
var ob = this;
// cancel hoverIntent timer if it exists
if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); }
// if e.type === "mouseenter"
if (e.type === "mouseenter") {
// set "previous" X and Y position based on initial entry point
pX = ev.pageX; pY = ev.pageY;
// update "current" X and Y position based on mousemove
$(ob).on("mousemove.hoverIntent",track);
// start polling interval (self-calling timeout) to compare mouse coordinates over time
if (!ob.hoverIntent_s) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );}
// else e.type == "mouseleave"
} else {
// unbind expensive mousemove event
$(ob).off("mousemove.hoverIntent",track);
// if hoverIntent state is true, then call the mouseOut function after the specified delay
if (ob.hoverIntent_s) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );}
}
};
// listen for mouseenter and mouseleave
return this.on({'mouseenter.hoverIntent':handleHover,'mouseleave.hoverIntent':handleHover}, cfg.selector);
};
})(jQuery);

5
static/js/main.js

@ -43,6 +43,7 @@ require.config({
'avltree': 'libs/avltree', 'avltree': 'libs/avltree',
'injectCSS': 'libs/jquery/jquery.injectCSS', 'injectCSS': 'libs/jquery/jquery.injectCSS',
'mobile-events': 'libs/jquery/jquery.mobile-events', 'mobile-events': 'libs/jquery/jquery.mobile-events',
'hoverIntent': 'libs/jquery/jquery.hoverIntent',
'jed': 'libs/jed', 'jed': 'libs/jed',
'audiocontext': 'libs/audiocontext', 'audiocontext': 'libs/audiocontext',
'rAF': 'libs/rAF', 'rAF': 'libs/rAF',
@ -112,6 +113,10 @@ require.config({
deps: ['jquery'], deps: ['jquery'],
exports: '$' exports: '$'
}, },
'hoverIntent': {
deps: ['jquery'],
exports: '$'
},
'sjcl': { 'sjcl': {
exports: 'sjcl' exports: 'sjcl'
}, },

2
static/partials/buddycondensed.html

@ -1,6 +1,6 @@
<div id="buddycondensed"> <div id="buddycondensed">
<div class="buddycondensed buddy"> <div class="buddycondensed buddy">
<span class="desc" ng-if="listOverDefault().length > maxBuddiesToShow">+ {{listOverDefault().length - maxBuddiesToShow}} {{_("more")}}</span> <span class="desc" ng-class="{overNum:listOverDefault().length > 0}">+ {{listOverDefault().length}} {{_("more")}}</span>
<div class="defaultDisplayNum pull-left"> <div class="defaultDisplayNum pull-left">
<span ng-repeat="buddy in listDefault()"> <span ng-repeat="buddy in listDefault()">
<span class="buddyPicture"> <span class="buddyPicture">

Loading…
Cancel
Save