added hover service

This commit is contained in:
Misko Hevery 2010-04-05 20:53:33 -07:00
parent 1c670b2a7c
commit 2107eafcde
9 changed files with 102 additions and 25 deletions

View file

@ -2,12 +2,13 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<link rel="stylesheet" type="text/css" href="style.css"></link> <link rel="stylesheet" type="text/css" href="style.css"></link>
<!--<script type="text/javascript" src="../lib/jquery/jquery-1.4.2.js"></script>-->
<script type="text/javascript" src="../src/angular-bootstrap.js#autobind"></script> <script type="text/javascript" src="../src/angular-bootstrap.js#autobind"></script>
</head> </head>
<body ng-init="$window.$scope = this"> <body ng-init="$window.$scope = this">
<table> <table>
<tr> <tr>
<th>Description</th> <th width="330">Description</th>
<th>Test</th> <th>Test</th>
<th>Result</th> <th>Result</th>
</tr> </tr>

View file

@ -313,8 +313,10 @@ function merge(src, dst) {
function compile(element, parentScope, overrides) { function compile(element, parentScope, overrides) {
var compiler = new Compiler(angularTextMarkup, angularAttrMarkup, angularDirective, angularWidget); var compiler = new Compiler(angularTextMarkup, angularAttrMarkup, angularDirective, angularWidget);
$element = jqLite(element); $element = jqLite(element),
return compiler.compile($element)($element, parentScope, overrides); parent = extend({}, parentScope);
parent.$element = $element;
return compiler.compile($element)($element, parent, overrides);
} }
///////////////////////////////////////////////// /////////////////////////////////////////////////
@ -340,6 +342,8 @@ function toKeyValue(obj) {
function angularInit(config){ function angularInit(config){
if (config.autobind) { if (config.autobind) {
compile(window.document, null, {'$config':config}).$init(); var scope = compile(window.document, null, {'$config':config});
scope.$browser.addCss('../css/angular.css');
scope.$init();
} }
} }

View file

@ -1,17 +1,9 @@
var browserSingleton; var browserSingleton;
angularService('$browser', function browserFactory(){ angularService('$browser', function browserFactory(){
if (!browserSingleton) { if (!browserSingleton) {
var XHR = XMLHttpRequest; browserSingleton = new Browser(window.location, window.document);
if (isUndefined(XHR)) {
XHR = function () {
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
throw new Error("This browser does not support XMLHttpRequest.");
};
}
browserSingleton = new Browser(window.location, XHR);
browserSingleton.startUrlWatcher(); browserSingleton.startUrlWatcher();
browserSingleton.bind();
} }
return browserSingleton; return browserSingleton;
}); });

View file

@ -3,18 +3,52 @@
// Browser // Browser
////////////////////////////// //////////////////////////////
function Browser(location, XHR) { function Browser(location, document) {
this.location = location;
this.delay = 25; this.delay = 25;
this.XHR = XHR; this.expectedUrl = location.href;
this.urlListeners = [];
this.hoverListener = noop;
this.XHR = XMLHttpRequest || function () {
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
throw new Error("This browser does not support XMLHttpRequest.");
};
this.setTimeout = function(fn, delay) { this.setTimeout = function(fn, delay) {
window.setTimeout(fn, delay); window.setTimeout(fn, delay);
}; };
this.expectedUrl = location.href;
this.listeners = []; this.location = location;
this.document = jqLite(document);
this.body = jqLite(document.body);
} }
Browser.prototype = { Browser.prototype = {
bind: function() {
var self = this;
self.document.bind("mouseover", function(event){
self.hoverListener(jqLite(event.target), true);
return true;
});
self.document.bind("mouseleave mouseout click dblclick keypress keyup", function(event){
self.hoverListener(jqLite(event.target), false);
return true;
});
},
hover: function(hoverListener) {
this.hoverListener = hoverListener;
},
addCss: function(url) {
var head = jqLite(this.document[0].getElementsByTagName('head')[0]),
link = jqLite('<link rel="stylesheet" type="text/css"></link>');
link.attr('href', url);
head.append(link);
},
xhr: function(method, url, callback){ xhr: function(method, url, callback){
var xhr = new this.XHR(); var xhr = new this.XHR();
xhr.open(method, url, true); xhr.open(method, url, true);
@ -27,14 +61,14 @@ Browser.prototype = {
}, },
watchUrl: function(fn){ watchUrl: function(fn){
this.listeners.push(fn); this.urlListeners.push(fn);
}, },
startUrlWatcher: function() { startUrlWatcher: function() {
var self = this; var self = this;
(function pull () { (function pull () {
if (self.expectedUrl !== self.location.href) { if (self.expectedUrl !== self.location.href) {
foreach(self.listeners, function(listener){ foreach(self.urlListeners, function(listener){
try { try {
listener(self.location.href); listener(self.location.href);
} catch (e) { } catch (e) {

View file

@ -47,7 +47,7 @@
addScript("/Parser.js"); addScript("/Parser.js");
addScript("/Resource.js"); addScript("/Resource.js");
addScript("/Browser.js"); addScript("/Browser.js");
addScript("/~AngularPublic.js"); addScript("/AngularPublic.js");
// Extension points // Extension points
addScript("/apis.js"); addScript("/apis.js");

View file

@ -78,7 +78,7 @@ JQLite.prototype = {
bind[type] = eventHandler = function(event) { bind[type] = eventHandler = function(event) {
var bubbleEvent = false; var bubbleEvent = false;
foreach(eventHandler.fns, function(fn){ foreach(eventHandler.fns, function(fn){
bubbleEvent = bubbleEvent || fn.apply(self, arguments); bubbleEvent = bubbleEvent || fn.call(self, event);
}); });
if (!bubbleEvent) { if (!bubbleEvent) {
event.preventDefault(); event.preventDefault();

View file

@ -44,3 +44,46 @@ angularService("$location", function(browser){
return location; return location;
}, {inject: ['$browser']}); }, {inject: ['$browser']});
angularService("$hover", function(browser) {
var tooltip, self = this, error, width = 300, arrowWidth = 10;
browser.hover(function(element, show){
if (show && (error = element.attr('ng-error'))) {
if (!tooltip) {
tooltip = {
callout: jqLite('<div id="ng-callout"></div>'),
arrow: jqLite('<div></div>'),
title: jqLite('<div class="ng-title"></div>'),
content: jqLite('<div class="ng-content"></div>')
};
tooltip.callout.append(tooltip.arrow);
tooltip.callout.append(tooltip.title);
tooltip.callout.append(tooltip.content);
self.$browser.body.append(tooltip.callout);
}
var docRect = self.$browser.body[0].getBoundingClientRect(),
elementRect = element[0].getBoundingClientRect(),
leftSpace = docRect.right - elementRect.right - arrowWidth;
tooltip.title.text(element.hasClass("ng-exception") ? "EXCEPTION:" : "Validation error...");
tooltip.content.text(error);
if (leftSpace < width) {
tooltip.arrow.addClass('ng-arrow-right');
tooltip.arrow.css({left: (width + 1)+'px'});
tooltip.callout.css({
left: (elementRect.left - arrowWidth - width - 4) + "px",
top: (elementRect.top - 3) + "px",
width: width + "px"
});
} else {
tooltip.arrow.addClass('ng-arrow-left');
tooltip.callout.css({
left: (elementRect.right + arrowWidth) + "px",
top: (elementRect.top - 3) + "px",
width: width + "px"
});
}
} else if (tooltip) {
tooltip.callout.remove();
tooltip = null;
}
});
}, {inject:['$browser']});

View file

@ -3,7 +3,7 @@ BrowserTest = TestCase('BrowserTest');
BrowserTest.prototype.testUrlWatcher = function () { BrowserTest.prototype.testUrlWatcher = function () {
expectAsserts(2); expectAsserts(2);
var location = {href:"http://server", hash:""}; var location = {href:"http://server", hash:""};
var watcher = new Browser(location); var watcher = new Browser(location, {});
watcher.delay = 1; watcher.delay = 1;
watcher.watchUrl(function(url){ watcher.watchUrl(function(url){
assertEquals('http://getangular.test', url); assertEquals('http://getangular.test', url);

View file

@ -8,7 +8,7 @@ function MockBrowser() {
var expect = expectations[method] || {}; var expect = expectations[method] || {};
var response = expect[url]; var response = expect[url];
if (!response) { if (!response) {
throw "Unexepected request for mothod '" + method + "' and url '" + url + "'."; throw "Unexepected request for method '" + method + "' and url '" + url + "'.";
} }
requests.push(function(){ requests.push(function(){
callback(200, response); callback(200, response);
@ -32,6 +32,9 @@ function MockBrowser() {
} }
MockBrowser.prototype = { MockBrowser.prototype = {
hover: function(onHover) {
},
getUrl: function(){ getUrl: function(){
return this.url; return this.url;
}, },