$location = {{$location}}
- - * scope.$location.href = 'http://www.angularjs.org/path#a/b' - *- * immediately after this call, other properties are still the old ones... - * - * This method checks the changes and update location to the consistent state - */ - function sync() { - if (!equals(location, lastLocation)) { - if (location.href != lastLocation.href) { - update(location.href); - return; - } - if (location.hash != lastLocation.hash) { - var hash = parseHash(location.hash); - updateHash(hash.hashPath, hash.hashSearch); - } else { - location.hash = composeHash(location); - location.href = composeHref(location); - } - update(location.href); - } - } - - - /** - * If location has changed, update the browser - * This method is called at the end of $eval() phase - */ - function updateBrowser() { - sync(); - - if ($browser.getUrl() != location.href) { - $browser.setUrl(location.href); - copy(location, lastLocation); - } - } - - /** - * Compose href string from a location object - * - * @param {Object} loc The location object with all properties - * @return {string} Composed href - */ - function composeHref(loc) { - var url = toKeyValue(loc.search); - var port = (loc.port == DEFAULT_PORTS[loc.protocol] ? _null : loc.port); - - return loc.protocol + '://' + loc.host + - (port ? ':' + port : '') + loc.path + - (url ? '?' + url : '') + (loc.hash ? '#' + loc.hash : ''); - } - - /** - * Compose hash string from location object - * - * @param {Object} loc Object with hashPath and hashSearch properties - * @return {string} Hash string - */ - function composeHash(loc) { - var hashSearch = toKeyValue(loc.hashSearch); - //TODO: temporary fix for issue #158 - return escape(loc.hashPath).replace(/%21/gi, '!').replace(/%3A/gi, ':').replace(/%24/gi, '$') + - (hashSearch ? '?' + hashSearch : ''); - } - - /** - * Parse href string into location object - * - * @param {string} href - * @return {Object} The location object - */ - function parseHref(href) { - var loc = {}; - var match = URL_MATCH.exec(href); - - if (match) { - loc.href = href.replace(/#$/, ''); - loc.protocol = match[1]; - loc.host = match[3] || ''; - loc.port = match[5] || DEFAULT_PORTS[loc.protocol] || _null; - loc.path = match[6] || ''; - loc.search = parseKeyValue(match[8]); - loc.hash = match[10] || ''; - - extend(loc, parseHash(loc.hash)); - } - - return loc; - } - - /** - * Parse hash string into object - * - * @param {string} hash - */ - function parseHash(hash) { - var h = {}; - var match = HASH_MATCH.exec(hash); - - if (match) { - h.hash = hash; - h.hashPath = unescape(match[1] || ''); - h.hashSearch = parseKeyValue(match[3]); - } - - return h; - } -}, ['$browser']); - - -/** - * @workInProgress - * @ngdoc service - * @name angular.service.$log - * @requires $window - * - * @description - * Simple service for logging. Default implementation writes the message - * into the browser's console (if present). - * - * The main purpose of this service is to simplify debugging and troubleshooting. - * - * @example -
Reload this page with open console, enter text and hit the log button...
- Message: - - - - - -angular.service('$updateView').delay = 10
- *
- * The delay is there so that multiple updates to the model which occur sufficiently close
- * together can be merged into a single update.
- *
- * You don't usually call '$updateView' directly since angular does it for you in most cases,
- * but there are some cases when you need to call it.
- *
- * - `$updateView()` called automatically by angular:
- * - Your Application Controllers: Your controller code is called by angular and hence
- * angular is aware that you may have changed the model.
- * - Your Services: Your service is usually called by your controller code, hence same rules
- * apply.
- * - May need to call `$updateView()` manually:
- * - Widgets / Directives: If you listen to any DOM events or events on any third party
- * libraries, then angular is not aware that you may have changed state state of the
- * model, and hence you need to call '$updateView()' manually.
- * - 'setTimeout'/'XHR': If you call 'setTimeout' (instead of {@link angular.service.$defer})
- * or 'XHR' (instead of {@link angular.service.$xhr}) then you may be changing the model
- * without angular knowledge and you may need to call '$updateView()' directly.
- *
- * NOTE: if you wish to update the view immediately (without delay), you can do so by calling
- * {@link scope.$eval} at any time from your code:
- * scope.$root.$eval()- * - * In unit-test mode the update is instantaneous and synchronous to simplify writing tests. - * - */ - -function serviceUpdateViewFactory($browser){ - var rootScope = this; - var scheduled; - function update(){ - scheduled = false; - rootScope.$eval(); - } - return $browser.isMock ? update : function(){ - if (!scheduled) { - scheduled = true; - $browser.defer(update, serviceUpdateViewFactory.delay); - } - }; -} -serviceUpdateViewFactory.delay = 25; - -angularServiceInject('$updateView', serviceUpdateViewFactory, ['$browser']); - -/** - * @workInProgress - * @ngdoc service - * @name angular.service.$hover - * @requires $browser - * @requires $document - * - * @description - * - * @example - */ -angularServiceInject("$hover", function(browser, document) { - var tooltip, self = this, error, width = 300, arrowWidth = 10, body = jqLite(document[0].body); - browser.hover(function(element, show){ - if (show && (error = element.attr(NG_EXCEPTION) || element.attr(NG_VALIDATION_ERROR))) { - if (!tooltip) { - tooltip = { - callout: jqLite(''), - arrow: jqLite(''), - title: jqLite(''), - content: jqLite('') - }; - tooltip.callout.append(tooltip.arrow); - tooltip.callout.append(tooltip.title); - tooltip.callout.append(tooltip.content); - body.append(tooltip.callout); - } - var docRect = 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({ - position: 'fixed', - 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({ - position: 'fixed', - left: (elementRect.right + arrowWidth) + "px", - top: (elementRect.top - 3) + "px", - width: width + "px" - }); - } - } else if (tooltip) { - tooltip.callout.remove(); - tooltip = _null; - } - }); -}, ['$browser', '$document'], EAGER); - -/** - * @workInProgress - * @ngdoc service - * @name angular.service.$invalidWidgets - * - * @description - * Keeps references to all invalid widgets found during validation. - * Can be queried to find whether there are any invalid widgets currently displayed. - * - * @example - */ -angularServiceInject("$invalidWidgets", function(){ - var invalidWidgets = []; - - - /** Remove an element from the array of invalid widgets */ - invalidWidgets.markValid = function(element){ - var index = indexOf(invalidWidgets, element); - if (index != -1) - invalidWidgets.splice(index, 1); - }; - - - /** Add an element to the array of invalid widgets */ - invalidWidgets.markInvalid = function(element){ - var index = indexOf(invalidWidgets, element); - if (index === -1) - invalidWidgets.push(element); - }; - - - /** Return count of all invalid widgets that are currently visible */ - invalidWidgets.visible = function() { - var count = 0; - forEach(invalidWidgets, function(widget){ - count = count + (isVisible(widget) ? 1 : 0); - }); - return count; - }; - - - /* At the end of each eval removes all invalid widgets that are not part of the current DOM. */ - this.$onEval(PRIORITY_LAST, function() { - for(var i = 0; i < invalidWidgets.length;) { - var widget = invalidWidgets[i]; - if (isOrphan(widget[0])) { - invalidWidgets.splice(i, 1); - if (widget.dealoc) widget.dealoc(); - } else { - i++; - } - } - }); - - - /** - * Traverses DOM element's (widget's) parents and considers the element to be an orphant if one of - * it's parents isn't the current window.document. - */ - function isOrphan(widget) { - if (widget == window.document) return false; - var parent = widget.parentNode; - return !parent || isOrphan(parent); - } - - return invalidWidgets; -}, [], EAGER); - - - -function switchRouteMatcher(on, when, dstName) { - var regex = '^' + when.replace(/[\.\\\(\)\^\$]/g, "\$1") + '$', - params = [], - dst = {}; - forEach(when.split(/\W/), function(param){ - if (param) { - var paramRegExp = new RegExp(":" + param + "([\\W])"); - if (regex.match(paramRegExp)) { - regex = regex.replace(paramRegExp, "([^\/]*)$1"); - params.push(param); - } - } - }); - var match = on.match(new RegExp(regex)); - if (match) { - forEach(params, function(name, index){ - dst[name] = match[index + 1]; - }); - if (dstName) this.$set(dstName, dst); - } - return match ? dst : _null; -} - -/** - * @workInProgress - * @ngdoc service - * @name angular.service.$route - * @requires $location - * - * @property {Object} current Reference to the current route definition. - * @property {Array.