r240 - in sandbox/nuiton-js-angularjs: . src/main/resources/META-INF/resources/nuiton-js-angular
Author: echatellier Date: 2013-11-18 11:24:25 +0100 (Mon, 18 Nov 2013) New Revision: 240 Url: http://nuiton.org/projects/nuiton-js/repository/revisions/240 Log: Update to angularjs 1.2.1 Added: sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-csp.css Modified: sandbox/nuiton-js-angularjs/pom.xml sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-animate.js sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-cookies.js sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-loader.js sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-mocks.js sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-resource.js sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-route.js sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-sanitize.js sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-touch.js sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular.js Modified: sandbox/nuiton-js-angularjs/pom.xml =================================================================== --- sandbox/nuiton-js-angularjs/pom.xml 2013-11-18 10:07:56 UTC (rev 239) +++ sandbox/nuiton-js-angularjs/pom.xml 2013-11-18 10:24:25 UTC (rev 240) @@ -14,9 +14,9 @@ </parent> <artifactId>nuiton-js-angularjs</artifactId> - <version>1.2.0-1</version> + <version>1.2.1-1-SNAPSHOT</version> - <name>Nuiton JS :: Angular</name> + <name>Nuiton JS :: AngularJS</name> <description>AngularJS jar packaging</description> <url>http://angularjs.org/</url> @@ -29,9 +29,9 @@ </licenses> <scm> - <connection>scm:svn:http://svn.nuiton.org/svn/nuiton-js/tags/nuiton-js-angularjs-1.2.0-1</connection> - <developerConnection>scm:svn:http://svn.nuiton.org/svn/nuiton-js/tags/nuiton-js-angularjs-1.2.0-1</developerConnection> - <url>http://www.nuiton.org/repositories/browse/nuiton-js/tags/nuiton-js-angularjs-1.2.0-1</url> + <connection>scm:svn:http://svn.nuiton.org/svn/nuiton-js/tags/nuiton-js-angularjs-1.2.1-1</connection> + <developerConnection>scm:svn:http://svn.nuiton.org/svn/nuiton-js/tags/nuiton-js-angularjs-1.2.1-1</developerConnection> + <url>http://www.nuiton.org/repositories/browse/nuiton-js/tags/nuiton-js-angularjs-1.2.1-1</url> </scm> </project> Modified: sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-animate.js =================================================================== --- sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-animate.js 2013-11-18 10:07:56 UTC (rev 239) +++ sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-animate.js 2013-11-18 10:24:25 UTC (rev 240) @@ -1,5 +1,5 @@ /** %%Ignore-License - * @license AngularJS v1.2.0 + * @license AngularJS v1.2.1 * (c) 2010-2012 Google, Inc. http://angularjs.org * License: MIT */ Modified: sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-cookies.js =================================================================== --- sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-cookies.js 2013-11-18 10:07:56 UTC (rev 239) +++ sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-cookies.js 2013-11-18 10:24:25 UTC (rev 240) @@ -1,5 +1,5 @@ /** %%Ignore-License - * @license AngularJS v1.2.0 + * @license AngularJS v1.2.1 * (c) 2010-2012 Google, Inc. http://angularjs.org * License: MIT */ Added: sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-csp.css =================================================================== --- sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-csp.css (rev 0) +++ sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-csp.css 2013-11-18 10:24:25 UTC (rev 240) @@ -0,0 +1,24 @@ +/* %%Ignore-License Include this file in your html if you are using the CSP mode. */ + +@charset "UTF-8"; + +[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], +.ng-cloak, .x-ng-cloak, +.ng-hide { + display: none !important; +} + +ng\:form { + display: block; +} + +/* The styles below ensure that the CSS transition will ALWAYS + * animate and close. A nasty bug occurs with CSS transitions where + * when the active class isn't set, or if the active class doesn't + * contain any styles to transition to, then, if ngAnimate is used, + * it will appear as if the webpage is broken due to the forever hanging + * animations. The clip (!ie) and zoom (ie) CSS properties are used + * since they trigger a transition without making the browser + * animate anything and they're both highly underused CSS properties */ +.ng-animate-start { clip:rect(0, auto, auto, 0); -ms-zoom:1.0001; } +.ng-animate-active { clip:rect(-1px, auto, auto, 0); -ms-zoom:1; } Property changes on: sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-csp.css ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Modified: sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-loader.js =================================================================== --- sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-loader.js 2013-11-18 10:07:56 UTC (rev 239) +++ sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-loader.js 2013-11-18 10:24:25 UTC (rev 240) @@ -1,12 +1,86 @@ /** %%Ignore-License - * @license AngularJS v1.2.0 + * @license AngularJS v1.2.1 * (c) 2010-2012 Google, Inc. http://angularjs.org * License: MIT */ -( +(function() {'use strict'; /** + * @description + * + * This object provides a utility for producing rich Error messages within + * Angular. It can be called as follows: + * + * var exampleMinErr = minErr('example'); + * throw exampleMinErr('one', 'This {0} is {1}', foo, bar); + * + * The above creates an instance of minErr in the example namespace. The + * resulting error will have a namespaced error code of example.one. The + * resulting error will replace {0} with the value of foo, and {1} with the + * value of bar. The object is not restricted in the number of arguments it can + * take. + * + * If fewer arguments are specified than necessary for interpolation, the extra + * interpolation markers will be preserved in the final string. + * + * Since data will be parsed statically during a build step, some restrictions + * are applied with respect to how minErr instances are created and called. + * Instances should have names of the form namespaceMinErr for a minErr created + * using minErr('namespace') . Error codes, namespaces and template strings + * should all be static strings, not variables or general expressions. + * + * @param {string} module The namespace to use for the new minErr instance. + * @returns {function(string, string, ...): Error} instance + */ + +function minErr(module) { + return function () { + var code = arguments[0], + prefix = '[' + (module ? module + ':' : '') + code + '] ', + template = arguments[1], + templateArgs = arguments, + stringify = function (obj) { + if (typeof obj === 'function') { + return obj.toString().replace(/ \{[\s\S]*$/, ''); + } else if (typeof obj === 'undefined') { + return 'undefined'; + } else if (typeof obj !== 'string') { + return JSON.stringify(obj); + } + return obj; + }, + message, i; + + message = prefix + template.replace(/\{\d+\}/g, function (match) { + var index = +match.slice(1, -1), arg; + + if (index + 2 < templateArgs.length) { + arg = templateArgs[index + 2]; + if (typeof arg === 'function') { + return arg.toString().replace(/ ?\{[\s\S]*$/, ''); + } else if (typeof arg === 'undefined') { + return 'undefined'; + } else if (typeof arg !== 'string') { + return toJson(arg); + } + return arg; + } + return match; + }); + + message = message + '\nhttp://errors.angularjs.org/1.2.1/' + + (module ? module + '/' : '') + code; + for (i = 2; i < arguments.length; i++) { + message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' + + encodeURIComponent(stringify(arguments[i])); + } + + return new Error(message); + }; +} + +/** * @ngdoc interface * @name angular.Module * @description @@ -17,6 +91,7 @@ function setupModuleLoader(window) { var $injectorMinErr = minErr('$injector'); + var ngMinErr = minErr('ng'); function ensure(obj, name, factory) { return obj[name] || (obj[name] = factory()); @@ -53,7 +128,7 @@ * myModule.value('appName', 'MyCoolApp'); * * // configure existing services inside initialization blocks. - * myModule.config(function($locationProvider) {'use strict'; + * myModule.config(function($locationProvider) { * // Configure existing providers * $locationProvider.hashPrefix('!'); * }); @@ -77,6 +152,12 @@ * @returns {module} new module with the {@link angular.Module} api. */ return function module(name, requires, configFn) { + var assertNotHasOwnProperty = function(name, context) { + if (name === 'hasOwnProperty') { + throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context); + } + }; + assertNotHasOwnProperty(name, 'module'); if (requires && modules.hasOwnProperty(name)) { modules[name] = null; @@ -301,7 +382,8 @@ } -)(window); +setupModuleLoader(window); +})(window); /** * Closure compiler type information Modified: sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-mocks.js =================================================================== --- sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-mocks.js 2013-11-18 10:07:56 UTC (rev 239) +++ sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-mocks.js 2013-11-18 10:24:25 UTC (rev 240) @@ -1,7 +1,7 @@ 'use strict'; /** %%Ignore-License - * @license AngularJS v1.2.0 + * @license AngularJS v1.2.1 * (c) 2010-2012 Google, Inc. http://angularjs.org * License: MIT * @@ -1659,21 +1659,6 @@ /** * @ngdoc method - * @name ngMock.$timeout#flushNext - * @methodOf ngMock.$timeout - * @description - * - * Flushes the next timeout in the queue and compares it to the provided delay - * - * @param {number=} expectedDelay the delay value that will be asserted against the delay of the - * next timeout function - */ - $delegate.flushNext = function(expectedDelay) { - $browser.defer.flushNext(expectedDelay); - }; - - /** - * @ngdoc method * @name ngMock.$timeout#verifyNoPendingTasks * @methodOf ngMock.$timeout * @description @@ -2127,4 +2112,4 @@ } } }; -})(window); \ No newline at end of file +})(window); Modified: sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-resource.js =================================================================== --- sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-resource.js 2013-11-18 10:07:56 UTC (rev 239) +++ sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-resource.js 2013-11-18 10:24:25 UTC (rev 240) @@ -1,5 +1,5 @@ /** %%Ignore-License - * @license AngularJS v1.2.0 + * @license AngularJS v1.2.1 * (c) 2010-2012 Google, Inc. http://angularjs.org * License: MIT */ @@ -7,6 +7,28 @@ var $resourceMinErr = angular.$$minErr('$resource'); +// Helper functions and regex to lookup a dotted path on an object +// stopping at undefined/null. The path must be composed of ASCII +// identifiers (just like $parse) +var MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/; + +function isValidDottedPath(path) { + return (path != null && path !== '' && path !== 'hasOwnProperty' && + MEMBER_NAME_REGEX.test('.' + path)); +} + +function lookupDottedPath(obj, path) { + if (!isValidDottedPath(path)) { + throw $resourceMinErr('badmember', 'Dotted member path "@{0}" is invalid.', path); + } + var keys = path.split('.'); + for (var i = 0, ii = keys.length; i < ii && obj !== undefined; i++) { + var key = keys[i]; + obj = (obj !== null) ? obj[key] : undefined; + } + return obj; +} + /** * @ngdoc overview * @name ngResource @@ -134,7 +156,7 @@ * usually the resource is assigned to a model which is then rendered by the view. Having an empty * object results in no rendering, once the data arrives from the server then the object is * populated with the data and the view automatically re-renders itself showing the new data. This - * means that in most case one never has to write a callback function for the action methods. + * means that in most cases one never has to write a callback function for the action methods. * * The action methods on the class object or instance object can be invoked with the following * parameters: @@ -236,61 +258,10 @@ }); }); </pre> - - * # Buzz client - - Let's look at what a buzz client created with the `$resource` service looks like: - <doc:example> - <doc:source jsfiddle="false"> - <script> - function BuzzController($resource) { - this.userId = 'googlebuzz'; - this.Activity = $resource( - 'https://www.googleapis.com/buzz/v1/activities/:userId/:visibility/:activityI...', - {alt:'json', callback:'JSON_CALLBACK'}, - { - get:{method:'JSONP', params:{visibility:'@self'}}, - replies: {method:'JSONP', params:{visibility:'@self', comments:'@comments'}} - } - ); - } - - BuzzController.prototype = { - fetch: function() { - this.activities = this.Activity.get({userId:this.userId}); - }, - expandReplies: function(activity) { - activity.replies = this.Activity.replies({userId:this.userId, activityId:activity.id}); - } - }; - BuzzController.$inject = ['$resource']; - </script> - - <div ng-controller="BuzzController"> - <input ng-model="userId"/> - <button ng-click="fetch()">fetch</button> - <hr/> - <div ng-repeat="item in activities.data.items"> - <h1 style="font-size: 15px;"> - <img src="{{item.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/> - <a href="{{item.actor.profileUrl}}">{{item.actor.name}}</a> - <a href ng-click="expandReplies(item)" style="float: right;">Expand replies: - {{item.links.replies[0].count}}</a> - </h1> - {{item.object.content | html}} - <div ng-repeat="reply in item.replies.data.items" style="margin-left: 20px;"> - <img src="{{reply.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/> - <a href="{{reply.actor.profileUrl}}">{{reply.actor.name}}</a>: {{reply.content | html}} - </div> - </div> - </div> - </doc:source> - <doc:scenario> - </doc:scenario> - </doc:example> */ angular.module('ngResource', ['ng']). - factory('$resource', ['$http', '$parse', '$q', function($http, $parse, $q) { + factory('$resource', ['$http', '$q', function($http, $q) { + var DEFAULT_ACTIONS = { 'get': {method:'GET'}, 'save': {method:'POST'}, @@ -302,10 +273,7 @@ forEach = angular.forEach, extend = angular.extend, copy = angular.copy, - isFunction = angular.isFunction, - getter = function(obj, path) { - return $parse(path)(obj); - }; + isFunction = angular.isFunction; /** * We need our custom method because encodeURIComponent is too aggressive and doesn't follow @@ -420,7 +388,7 @@ forEach(actionParams, function(value, key){ if (isFunction(value)) { value = value(); } ids[key] = value && value.charAt && value.charAt(0) == '@' ? - getter(data, value.substr(1)) : value; + lookupDottedPath(data, value.substr(1)) : value; }); return ids; } Modified: sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-route.js =================================================================== --- sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-route.js 2013-11-18 10:07:56 UTC (rev 239) +++ sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-route.js 2013-11-18 10:24:25 UTC (rev 240) @@ -1,5 +1,5 @@ /** %%Ignore-License - * @license AngularJS v1.2.0 + * @license AngularJS v1.2.1 * (c) 2010-2012 Google, Inc. http://angularjs.org * License: MIT */ @@ -809,8 +809,7 @@ terminal: true, priority: 400, transclude: 'element', - compile: function(element, attr, linker) { - return function(scope, $element, attr) { + link: function(scope, $element, attr, ctrl, $transclude) { var currentScope, currentElement, autoScrollExp = attr.autoscroll, @@ -836,7 +835,7 @@ if (template) { var newScope = scope.$new(); - linker(newScope, function(clone) { + $transclude(newScope, function(clone) { clone.html(template); $animate.enter(clone, null, currentElement || $element, function onNgViewEnter () { if (angular.isDefined(autoScrollExp) @@ -871,7 +870,6 @@ cleanupLastView(); } } - }; } }; } Modified: sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-sanitize.js =================================================================== --- sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-sanitize.js 2013-11-18 10:07:56 UTC (rev 239) +++ sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-sanitize.js 2013-11-18 10:24:25 UTC (rev 240) @@ -1,5 +1,5 @@ /** %%Ignore-License - * @license AngularJS v1.2.0 + * @license AngularJS v1.2.1 * (c) 2010-2012 Google, Inc. http://angularjs.org * License: MIT */ Modified: sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-touch.js =================================================================== --- sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-touch.js 2013-11-18 10:07:56 UTC (rev 239) +++ sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular-touch.js 2013-11-18 10:24:25 UTC (rev 240) @@ -1,5 +1,5 @@ /** %%Ignore-License - * @license AngularJS v1.2.0 + * @license AngularJS v1.2.1 * (c) 2010-2012 Google, Inc. http://angularjs.org * License: MIT */ Modified: sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular.js =================================================================== --- sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular.js 2013-11-18 10:07:56 UTC (rev 239) +++ sandbox/nuiton-js-angularjs/src/main/resources/META-INF/resources/nuiton-js-angular/angular.js 2013-11-18 10:24:25 UTC (rev 240) @@ -1,5 +1,5 @@ /** %%Ignore-License - * @license AngularJS v1.2.0 + * @license AngularJS v1.2.1 * (c) 2010-2012 Google, Inc. http://angularjs.org * License: MIT */ @@ -40,11 +40,11 @@ template = arguments[1], templateArgs = arguments, stringify = function (obj) { - if (isFunction(obj)) { + if (typeof obj === 'function') { return obj.toString().replace(/ \{[\s\S]*$/, ''); - } else if (isUndefined(obj)) { + } else if (typeof obj === 'undefined') { return 'undefined'; - } else if (!isString(obj)) { + } else if (typeof obj !== 'string') { return JSON.stringify(obj); } return obj; @@ -56,11 +56,11 @@ if (index + 2 < templateArgs.length) { arg = templateArgs[index + 2]; - if (isFunction(arg)) { + if (typeof arg === 'function') { return arg.toString().replace(/ ?\{[\s\S]*$/, ''); - } else if (isUndefined(arg)) { + } else if (typeof arg === 'undefined') { return 'undefined'; - } else if (!isString(arg)) { + } else if (typeof arg !== 'string') { return toJson(arg); } return arg; @@ -68,7 +68,7 @@ return match; }); - message = message + '\nhttp://errors.angularjs.org/' + version.full + '/' + + message = message + '\nhttp://errors.angularjs.org/1.2.1/' + (module ? module + '/' : '') + code; for (i = 2; i < arguments.length; i++) { message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' + @@ -1429,6 +1429,7 @@ function setupModuleLoader(window) { var $injectorMinErr = minErr('$injector'); + var ngMinErr = minErr('ng'); function ensure(obj, name, factory) { return obj[name] || (obj[name] = factory()); @@ -1489,6 +1490,12 @@ * @returns {module} new module with the {@link angular.Module} api. */ return function module(name, requires, configFn) { + var assertNotHasOwnProperty = function(name, context) { + if (name === 'hasOwnProperty') { + throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context); + } + }; + assertNotHasOwnProperty(name, 'module'); if (requires && modules.hasOwnProperty(name)) { modules[name] = null; @@ -1801,11 +1808,11 @@ * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat". */ var version = { - full: '1.2.0', // all of these placeholder strings will be replaced by grunt's + full: '1.2.1', // all of these placeholder strings will be replaced by grunt's major: 1, // package task - minor: "NG_VERSION_MINOR", - dot: 0, - codeName: 'timely-delivery' + minor: 2, + dot: 1, + codeName: 'underscore-empathy' }; @@ -4696,8 +4703,9 @@ * When there are multiple directives defined on a single DOM element, sometimes it * is necessary to specify the order in which the directives are applied. The `priority` is used * to sort the directives before their `compile` functions get called. Priority is defined as a - * number. Directives with greater numerical `priority` are compiled first. The order of directives with - * the same priority is undefined. The default priority is `0`. + * number. Directives with greater numerical `priority` are compiled first. Pre-link functions + * are also run in priority order, but post-link functions are run in reverse order. The order + * of directives with the same priority is undefined. The default priority is `0`. * * #### `terminal` * If set to true then the current `priority` will be the last set of directives @@ -4758,8 +4766,9 @@ * * `$scope` - Current scope associated with the element * * `$element` - Current element * * `$attrs` - Current attributes object for the element - * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope: - * `function(cloneLinkingFn)`. + * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope. + * The scope can be overridden by an optional first argument. + * `function([scope], cloneLinkingFn)`. * * * #### `require` @@ -4852,7 +4861,7 @@ * * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared * between all directive compile functions. * - * * `transclude` - A transclude linking function: `function(scope, cloneLinkingFn)`. + * * `transclude` - [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)` * * <div class="alert alert-warning"> * **Note:** The template instance and the link instance may be different objects if the template has @@ -4861,6 +4870,12 @@ * should be done in a linking function rather than in a compile function. * </div> * + * <div class="alert alert-error"> + * **Note:** The `transclude` function that is passed to the compile function is deperecated, as it + * e.g. does not know about the right outer scope. Please use the transclude function that is passed + * to the link function instead. + * </div> + * A compile function can have a return value which can be either a function or an object. * * * returning a (post-link) function - is equivalent to registering the linking function via the @@ -4875,7 +4890,7 @@ * This property is used only if the `compile` property is not defined. * * <pre> - * function link(scope, iElement, iAttrs, controller) { ... } + * function link(scope, iElement, iAttrs, controller, transcludeFn) { ... } * </pre> * * The link function is responsible for registering DOM listeners as well as updating the DOM. It is @@ -4896,6 +4911,10 @@ * element defines a controller. The controller is shared among all the directives, which allows * the directives to use the controllers as a communication channel. * + * * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope. + * The scope can be overridden by an optional first argument. This is the same as the `$transclude` + * parameter of directive controllers. + * `function([scope], cloneLinkingFn)`. * * * #### Pre-linking function @@ -5401,7 +5420,7 @@ var compositeLinkFn = compileNodes($compileNodes, transcludeFn, $compileNodes, maxPriority, ignoreDirective, previousCompileContext); - return function publicLinkFn(scope, cloneConnectFn){ + return function publicLinkFn(scope, cloneConnectFn, transcludeControllers){ assertArg(scope, 'scope'); // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart // and sometimes changes the structure of the DOM. @@ -5409,6 +5428,10 @@ ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!! : $compileNodes; + forEach(transcludeControllers, function(instance, name) { + $linkNode.data('$' + name + 'Controller', instance); + }); + // Attach scope only to non-text nodes. for(var i = 0, ii = $linkNode.length; i<ii; i++) { var node = $linkNode[i]; @@ -5507,15 +5530,7 @@ childTranscludeFn = nodeLinkFn.transclude; if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) { nodeLinkFn(childLinkFn, childScope, node, $rootElement, - (function(transcludeFn) { - return function(cloneFn) { - var transcludeScope = scope.$new(); - transcludeScope.$$transcluded = true; - - return transcludeFn(transcludeScope, cloneFn). - on('$destroy', bind(transcludeScope, transcludeScope.$destroy)); - }; - })(childTranscludeFn || transcludeFn) + createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn) ); } else { nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn); @@ -5527,7 +5542,24 @@ } } + function createBoundTranscludeFn(scope, transcludeFn) { + return function boundTranscludeFn(transcludedScope, cloneFn, controllers) { + var scopeCreated = false; + if (!transcludedScope) { + transcludedScope = scope.$new(); + transcludedScope.$$transcluded = true; + scopeCreated = true; + } + + var clone = transcludeFn(transcludedScope, cloneFn, controllers); + if (scopeCreated) { + clone.on('$destroy', bind(transcludedScope, transcludedScope.$destroy)); + } + return clone; + }; + } + /** * Looks for directives on the given node and adds them to the directive collection which is * sorted. @@ -5664,9 +5696,9 @@ * @returns {Function} */ function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) { - return function(scope, element, attrs, controllers) { + return function(scope, element, attrs, controllers, transcludeFn) { element = groupScan(element[0], attrStart, attrEnd); - return linkFn(scope, element, attrs, controllers); + return linkFn(scope, element, attrs, controllers, transcludeFn); }; } @@ -5703,7 +5735,9 @@ controllerDirectives = previousCompileContext.controllerDirectives, newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective, templateDirective = previousCompileContext.templateDirective, - transcludeDirective = previousCompileContext.transcludeDirective, + nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective, + hasTranscludeDirective = false, + hasElementTranscludeDirective = false, $compileNode = templateAttrs.$$element = jqLite(compileNode), directive, directiveName, @@ -5754,15 +5788,18 @@ } if (directiveValue = directive.transclude) { + hasTranscludeDirective = true; + // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion. // This option should only be used by directives that know how to how to safely handle element transclusion, // where the transcluded nodes are added or replaced after linking. if (!directive.$$tlb) { - assertNoDuplicate('transclusion', transcludeDirective, directive, $compileNode); - transcludeDirective = directive; + assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode); + nonTlbTranscludeDirective = directive; } if (directiveValue == 'element') { + hasElementTranscludeDirective = true; terminalPriority = directive.priority; $template = groupScan(compileNode, attrStart, attrEnd); $compileNode = templateAttrs.$$element = @@ -5778,9 +5815,9 @@ // - newIsolateScopeDirective or templateDirective - combining templates with // element transclusion doesn't make sense. // - // We need only transcludeDirective so that we prevent putting transclusion + // We need only nonTlbTranscludeDirective so that we prevent putting transclusion // on the same element more than once. - transcludeDirective: transcludeDirective + nonTlbTranscludeDirective: nonTlbTranscludeDirective }); } else { $template = jqLite(jqLiteClone(compileNode)).contents(); @@ -5849,7 +5886,7 @@ controllerDirectives: controllerDirectives, newIsolateScopeDirective: newIsolateScopeDirective, templateDirective: templateDirective, - transcludeDirective: transcludeDirective + nonTlbTranscludeDirective: nonTlbTranscludeDirective }); ii = directives.length; } else if (directive.compile) { @@ -5873,7 +5910,7 @@ } nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true; - nodeLinkFn.transclude = transcludeDirective && childTranscludeFn; + nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn; // might be normal or delayed nodeLinkFn depending on if templateUrl is present return nodeLinkFn; @@ -5900,7 +5937,7 @@ } - function getControllers(require, $element) { + function getControllers(require, $element, elementControllers) { var value, retrievalMethod = 'data', optional = false; if (isString(require)) { while((value = require.charAt(0)) == '^' || value == '?') { @@ -5910,13 +5947,12 @@ } optional = optional || value == '?'; } + value = null; - value = $element[retrievalMethod]('$' + require + 'Controller'); - - if ($element[0].nodeType == 8 && $element[0].$$controller) { // Transclusion comment node - value = value || $element[0].$$controller; - $element[0].$$controller = null; + if (elementControllers && retrievalMethod === 'data') { + value = elementControllers[require]; } + value = value || $element[retrievalMethod]('$' + require + 'Controller'); if (!value && !optional) { throw $compileMinErr('ctreq', @@ -5927,7 +5963,7 @@ } else if (isArray(require)) { value = []; forEach(require, function(require) { - value.push(getControllers(require, $element)); + value.push(getControllers(require, $element, elementControllers)); }); } return value; @@ -5935,7 +5971,7 @@ function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) { - var attrs, $element, i, ii, linkFn, controller, isolateScope; + var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn; if (compileNode === linkNode) { attrs = templateAttrs; @@ -6029,14 +6065,14 @@ } }); } - + transcludeFn = boundTranscludeFn && controllersBoundTransclude; if (controllerDirectives) { forEach(controllerDirectives, function(directive) { var locals = { $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope, $element: $element, $attrs: attrs, - $transclude: boundTranscludeFn + $transclude: transcludeFn }, controllerInstance; controller = directive.controller; @@ -6045,16 +6081,16 @@ } controllerInstance = $controller(controller, locals); - - // Directives with element transclusion and a controller need to attach controller - // to the comment node created by the compiler, but jQuery .data doesn't support - // attaching data to comment nodes so instead we set it directly on the element and - // remove it after we read it later. - if ($element[0].nodeType == 8) { // Transclusion comment node - $element[0].$$controller = controllerInstance; - } else { + // For directives with element transclusion the element is a comment, + // but jQuery .data doesn't support attaching data to comment nodes as it's hard to + // clean up (http://bugs.jquery.com/ticket/8335). + // Instead, we save the controllers for the element in a local hash and attach to .data + // later, once we have the actual element. + elementControllers[directive.name] = controllerInstance; + if (!hasElementTranscludeDirective) { $element.data('$' + directive.name + 'Controller', controllerInstance); } + if (directive.controllerAs) { locals.$scope[directive.controllerAs] = controllerInstance; } @@ -6066,7 +6102,7 @@ try { linkFn = preLinkFns[i]; linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs, - linkFn.require && getControllers(linkFn.require, $element)); + linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn); } catch (e) { $exceptionHandler(e, startingTag($element)); } @@ -6086,11 +6122,28 @@ try { linkFn = postLinkFns[i]; linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs, - linkFn.require && getControllers(linkFn.require, $element)); + linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn); } catch (e) { $exceptionHandler(e, startingTag($element)); } } + + // This is the function that is injected as `$transclude`. + function controllersBoundTransclude(scope, cloneAttachFn) { + var transcludeControllers; + + // no scope passed + if (arguments.length < 2) { + cloneAttachFn = scope; + scope = undefined; + } + + if (hasElementTranscludeDirective) { + transcludeControllers = elementControllers; + } + + return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers); + } } } @@ -6169,6 +6222,7 @@ dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value; } else if (key == 'style') { $element.attr('style', $element.attr('style') + ';' + value); + dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value; // `dst` will never contain hasOwnProperty as DOM parser won't let it. // You will get an "InvalidCharacterError: DOM Exception 5" error if you // have an attribute like "has-own-property" or "data-has-own-property", etc. @@ -6199,7 +6253,7 @@ $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}). success(function(content) { - var compileNode, tempTemplateAttrs, $template; + var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn; content = denormalizeTemplate(content); @@ -6244,7 +6298,7 @@ var scope = linkQueue.shift(), beforeTemplateLinkNode = linkQueue.shift(), linkRootElement = linkQueue.shift(), - controller = linkQueue.shift(), + boundTranscludeFn = linkQueue.shift(), linkNode = $compileNode[0]; if (beforeTemplateLinkNode !== beforeTemplateCompileNode) { @@ -6252,9 +6306,13 @@ linkNode = jqLiteClone(compileNode); replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode); } - + if (afterTemplateNodeLinkFn.transclude) { + childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude); + } else { + childBoundTranscludeFn = boundTranscludeFn; + } afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement, - controller); + childBoundTranscludeFn); } linkQueue = null; }). @@ -6262,14 +6320,14 @@ throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url); }); - return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, controller) { + return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) { if (linkQueue) { linkQueue.push(scope); linkQueue.push(node); linkQueue.push(rootElement); - linkQueue.push(controller); + linkQueue.push(boundTranscludeFn); } else { - afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, controller); + afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, boundTranscludeFn); } }; } @@ -6974,9 +7032,11 @@ * * # Caching * - * To enable caching, set the configuration property `cache` to `true`. When the cache is - * enabled, `$http` stores the response from the server in local cache. Next time the - * response is served from the cache without sending a request to the server. + * To enable caching, set the request configuration `cache` property to `true` (to use default + * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}). + * When the cache is enabled, `$http` stores the response from the server in the specified + * cache. The next time the same request is made, the response is served from the cache without + * sending a request to the server. * * Note that even if the response is served from cache, delivery of the data is asynchronous in * the same way that real requests are. @@ -6985,9 +7045,13 @@ * cache, but the cache is not populated yet, only one request to the server will be made and * the remaining requests will be fulfilled using the response from the first request. * - * A custom default cache built with $cacheFactory can be provided in $http.defaults.cache. - * To skip it, set configuration property `cache` to `false`. + * You can change the default cache to a new object (built with + * {@link ng.$cacheFactory `$cacheFactory`}) by updating the + * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set + * their `cache` property to `true` will now use this cache object. * + * If you set the default cache to `false` then only requests that specify their own custom + * cache object will be cached. * * # Interceptors * @@ -8251,8 +8315,8 @@ return segments.join('/'); } -function parseAbsoluteUrl(absoluteUrl, locationObj) { - var parsedUrl = urlResolve(absoluteUrl); +function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) { + var parsedUrl = urlResolve(absoluteUrl, appBase); locationObj.$$protocol = parsedUrl.protocol; locationObj.$$host = parsedUrl.hostname; @@ -8260,12 +8324,12 @@ } -function parseAppUrl(relativeUrl, locationObj) { +function parseAppUrl(relativeUrl, locationObj, appBase) { var prefixed = (relativeUrl.charAt(0) !== '/'); if (prefixed) { relativeUrl = '/' + relativeUrl; } - var match = urlResolve(relativeUrl); + var match = urlResolve(relativeUrl, appBase); locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ? match.pathname.substring(1) : match.pathname); locationObj.$$search = parseKeyValue(match.search); @@ -8320,7 +8384,7 @@ this.$$html5 = true; basePrefix = basePrefix || ''; var appBaseNoFile = stripFile(appBase); - parseAbsoluteUrl(appBase, this); + parseAbsoluteUrl(appBase, this, appBase); /** @@ -8335,7 +8399,7 @@ appBaseNoFile); } - parseAppUrl(pathUrl, this); + parseAppUrl(pathUrl, this, appBase); if (!this.$$path) { this.$$path = '/'; @@ -8387,7 +8451,7 @@ function LocationHashbangUrl(appBase, hashPrefix) { var appBaseNoFile = stripFile(appBase); - parseAbsoluteUrl(appBase, this); + parseAbsoluteUrl(appBase, this, appBase); /** @@ -8407,7 +8471,7 @@ throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url, hashPrefix); } - parseAppUrl(withoutHashUrl, this); + parseAppUrl(withoutHashUrl, this, appBase); this.$$compose(); }; @@ -9055,23 +9119,18 @@ // ------------------------------ // Angular expressions are generally considered safe because these expressions only have direct // access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by -// obtaining a reference to native JS functions such as the Function constructor, the global Window -// or Document object. In addition, many powerful functions for use by JavaScript code are -// published on scope that shouldn't be available from within an Angular expression. +// obtaining a reference to native JS functions such as the Function constructor. // // As an example, consider the following Angular expression: // // {}.toString.constructor(alert("evil JS code")) // // We want to prevent this type of access. For the sake of performance, during the lexing phase we -// disallow any "dotted" access to any member named "constructor" or to any member whose name begins -// or ends with an underscore. The latter allows one to exclude the private / JavaScript only API -// available on the scope and controllers from the context of an Angular expression. +// disallow any "dotted" access to any member named "constructor". // -// For reflective calls (a[b]), we check that the value of the lookup is not the Function -// constructor, Window or DOM node while evaluating the expression, which is a stronger but more -// expensive test. Since reflective calls are expensive anyway, this is not such a big deal compared -// to static dereferencing. +// For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor +// while evaluating the expression, which is a stronger but more expensive test. Since reflective +// calls are expensive anyway, this is not such a big deal compared to static dereferencing. // // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits // against the expression language, but not to prevent exploits that were enabled by exposing @@ -9085,20 +9144,12 @@ // In general, it is not possible to access a Window object from an angular expression unless a // window or some DOM object that has a reference to window is published onto a Scope. -function ensureSafeMemberName(name, fullExpression, allowConstructor) { - if (typeof name !== 'string' && toString.apply(name) !== "[object String]") { - return name; - } - if (name === "constructor" && !allowConstructor) { +function ensureSafeMemberName(name, fullExpression) { + if (name === "constructor") { throw $parseMinErr('isecfld', 'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}', fullExpression); } - if (name.charAt(0) === '_' || name.charAt(name.length-1) === '_') { - throw $parseMinErr('isecprv', - 'Referencing private fields in Angular expressions is disallowed! Expression: {0}', - fullExpression); - } return name; } @@ -9782,10 +9833,7 @@ return extend(function(self, locals) { var o = obj(self, locals), - // In the getter, we will not block looking up "constructor" by name in order to support user defined - // constructors. However, if value looked up is the Function constructor, we will still block it in the - // ensureSafeObject call right after we look up o[i] (a few lines below.) - i = ensureSafeMemberName(indexFn(self, locals), parser.text, true /* allowConstructor */), + i = indexFn(self, locals), v, p; if (!o) return undefined; @@ -9801,7 +9849,7 @@ return v; }, { assign: function(self, value, locals) { - var key = ensureSafeMemberName(indexFn(self, locals), parser.text); + var key = indexFn(self, locals); // prevent overwriting of Function.constructor which would break ensureSafeObject check var safe = ensureSafeObject(obj(self, locals), parser.text); return safe[key] = value; @@ -10461,7 +10509,7 @@ * // Propagate promise resolution to 'then' functions using $apply(). * $rootScope.$apply(); * expect(resolvedValue).toEqual(123); - * }); + * })); * </pre> */ function $QProvider() { @@ -12278,10 +12326,10 @@ * * <pre class="prettyprint"> * <input ng-model="userHtml"> - * <div ng-bind-html="{{userHtml}}"> + * <div ng-bind-html="userHtml"> * </pre> * - * Notice that `ng-bind-html` is bound to `{{userHtml}}` controlled by the user. With SCE + * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user. With SCE * disabled, this application allows the user to render arbitrary HTML into the DIV. * In a more realistic example, one may be rendering user comments, blog articles, etc. via * bindings. (HTML is just one example of a context where rendering user controlled input creates @@ -13202,8 +13250,14 @@ // exactly the behavior needed here. There is little value is mocking these out for this // service. var urlParsingNode = document.createElement("a"); +/* +Matches paths for file protocol on windows, +such as /C:/foo/bar, and captures only /foo/bar. +*/ +var windowsFilePathExp = /^\/?.*?:(\/.*)/; var originUrl = urlResolve(window.location.href, true); + /** * * Implementation Notes for non-IE browsers @@ -13222,7 +13276,7 @@ * browsers. However, the parsed components will not be set if the URL assigned did not specify * them. (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.) We * work around that by performing the parsing in a 2nd step by taking a previously normalized - * URL (e.g. by assining to a.href) and assigning it a.href again. This correctly populates the + * URL (e.g. by assigning to a.href) and assigning it a.href again. This correctly populates the * properties such as protocol, hostname, port, etc. * * IE7 does not normalize the URL when assigned to an anchor node. (Apparently, it does, if one @@ -13256,8 +13310,10 @@ * | pathname | The pathname, beginning with "/" * */ -function urlResolve(url) { - var href = url; +function urlResolve(url, base) { + var href = url, + pathname; + if (msie) { // Normalize before parse. Refer Implementation Notes on why this is // done in two steps on IE. @@ -13267,7 +13323,22 @@ urlParsingNode.setAttribute('href', href); - // $$urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils + /* + * In Windows, on an anchor node on documents loaded from + * the filesystem, the browser will return a pathname + * prefixed with the drive name ('/C:/path') when a + * pathname without a drive is set: + * * a.setAttribute('href', '/foo') + * * a.pathname === '/C:/foo' //true + * + * Inside of Angular, we're always using pathnames that + * do not include drive names for routing. + */ + + pathname = removeWindowsDriveName(urlParsingNode.pathname, url, base); + pathname = (pathname.charAt(0) === '/') ? pathname : '/' + pathname; + + // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils return { href: urlParsingNode.href, protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '', @@ -13276,8 +13347,7 @@ hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '', hostname: urlParsingNode.hostname, port: urlParsingNode.port, - pathname: urlParsingNode.pathname && urlParsingNode.pathname.charAt(0) === '/' ? - urlParsingNode.pathname : '/' + urlParsingNode.pathname + pathname: pathname }; } @@ -13295,6 +13365,26 @@ parsed.host === originUrl.host); } +function removeWindowsDriveName (path, url, base) { + var firstPathSegmentMatch; + + //Get the relative path from the input URL. + if (url.indexOf(base) === 0) { + url = url.replace(base, ''); + } + + /* + * The input URL intentionally contains a + * first path segment that ends with a colon. + */ + if (windowsFilePathExp.exec(url)) { + return path; + } + + firstPathSegmentMatch = windowsFilePathExp.exec(path); + return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path; +} + /** * @ngdoc object * @name ng.$window @@ -14811,7 +14901,7 @@ * @property {Object} $error Is an object hash, containing references to all invalid controls or * forms, where: * - * - keys are validation tokens (error names) — such as `required`, `url` or `email`), + * - keys are validation tokens (error names) — such as `required`, `url` or `email`, * - values are arrays of controls or forms that are invalid with given error. * * @description @@ -15996,6 +16086,11 @@ * } * ngModel.$formatters.push(formatter); * </pre> + * + * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the + * view value has changed. It is called with no arguments, and its return value is ignored. + * This can be used in place of additional $watches against the model value. + * * @property {Object} $error An object hash with all errors as keys. * * @property {boolean} $pristine True if user has not interacted with the control yet. @@ -16259,15 +16354,20 @@ * @methodOf ng.directive:ngModel.NgModelController * * @description - * Read a value from view. + * Update the view value. * - * This method should be called from within a DOM event handler. - * For example {@link ng.directive:input input} or + * This method should be called when the view value changes, typically from within a DOM event handler. + * For example {@link ng.directive:input input} and * {@link ng.directive:select select} directives call it. * - * It internally calls all `$parsers` (including validators) and updates the `$modelValue` and the actual model path. - * Lastly it calls all registered change listeners. + * It will update the $viewValue, then pass this value through each of the functions in `$parsers`, + * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to + * `$modelValue` and the **expression** specified in the `ng-model` attribute. + * + * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called. * + * Note that calling this function does not trigger a `$digest`. + * * @param {string} value Value from the view. */ this.$setViewValue = function(value) { @@ -16768,27 +16868,33 @@ * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate. * * @example - * Try it here: enter text in text box and watch the greeting change. - <doc:example module="ngBindHtmlExample" deps="angular-sanitize.js" > - <doc:source> - <script> - angular.module('ngBindHtmlExample', ['ngSanitize']) - - .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) { - $scope.myHTML = 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>'; - }]); - </script> + Try it here: enter text in text box and watch the greeting change. + + <example module="ngBindHtmlExample" deps="angular-sanitize.js"> + <file name="index.html"> <div ng-controller="ngBindHtmlCtrl"> <p ng-bind-html="myHTML"></p> </div> - </doc:source> - <doc:scenario> + </file> + + <file name="script.js"> + angular.module('ngBindHtmlExample', ['ngSanitize']) + + .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) { + $scope.myHTML = + 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>'; + }]); + </file> + + <file name="scenario.js"> it('should check ng-bind-html', function() { expect(using('.doc-example-live').binding('myHTML')). - toBe('I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>'); + toBe( + 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>' + ); }); - </doc:scenario> - </doc:example> + </file> + </example> */ var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) { return function(scope, element, attr) { @@ -16901,18 +17007,18 @@ * @example Example that demonstrates basic bindings via ngClass directive. <example> <file name="index.html"> - <p ng-class="{strike: strike, bold: bold, red: red}">Map Syntax Example</p> - <input type="checkbox" ng-model="bold"> bold - <input type="checkbox" ng-model="strike"> strike - <input type="checkbox" ng-model="red"> red + <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p> + <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br> + <input type="checkbox" ng-model="important"> important (apply "bold" class)<br> + <input type="checkbox" ng-model="error"> error (apply "red" class) <hr> <p ng-class="style">Using String Syntax</p> <input type="text" ng-model="style" placeholder="Type: bold strike red"> <hr> <p ng-class="[style1, style2, style3]">Using Array Syntax</p> - <input ng-model="style1" placeholder="Type: bold"><br> - <input ng-model="style2" placeholder="Type: strike"><br> - <input ng-model="style3" placeholder="Type: red"><br> + <input ng-model="style1" placeholder="Type: bold, strike or red"><br> + <input ng-model="style2" placeholder="Type: bold, strike or red"><br> + <input ng-model="style3" placeholder="Type: bold, strike or red"><br> </file> <file name="style.css"> .strike { @@ -16931,10 +17037,10 @@ expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/bold/); expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/red/); - input('bold').check(); + input('important').check(); expect(element('.doc-example-live p:first').prop('className')).toMatch(/bold/); - input('red').check(); + input('error').check(); expect(element('.doc-example-live p:first').prop('className')).toMatch(/red/); }); @@ -17780,7 +17886,7 @@ } /* - The transition styles can also be placed on the CSS base class above + The transition styles can also be placed on the CSS base class above */ .animate-if.ng-enter, .animate-if.ng-leave { -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; @@ -17806,22 +17912,21 @@ terminal: true, restrict: 'A', $$tlb: true, - compile: function (element, attr, transclude) { - return function ($scope, $element, $attr) { + link: function ($scope, $element, $attr, ctrl, $transclude) { var block, childScope; $scope.$watch($attr.ngIf, function ngIfWatchAction(value) { if (toBoolean(value)) { - - childScope = $scope.$new(); - transclude(childScope, function (clone) { - block = { - startNode: clone[0], - endNode: clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ') - }; - $animate.enter(clone, $element.parent(), $element); - }); - + if (!childScope) { + childScope = $scope.$new(); + $transclude(childScope, function (clone) { + block = { + startNode: clone[0], + endNode: clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ') + }; + $animate.enter(clone, $element.parent(), $element); + }); + } } else { if (childScope) { @@ -17835,7 +17940,6 @@ } } }); - }; } }; }]; @@ -17994,12 +18098,12 @@ priority: 400, terminal: true, transclude: 'element', - compile: function(element, attr, transclusion) { + compile: function(element, attr) { var srcExp = attr.ngInclude || attr.src, onloadExp = attr.onload || '', autoScrollExp = attr.autoscroll; - return function(scope, $element) { + return function(scope, $element, $attr, ctrl, $transclude) { var changeCounter = 0, currentScope, currentElement; @@ -18028,7 +18132,7 @@ if (thisChangeId !== changeCounter) return; var newScope = scope.$new(); - transclusion(newScope, function(clone) { + $transclude(newScope, function(clone) { cleanupLastIncludeContent(); currentScope = newScope; @@ -18557,8 +18661,7 @@ priority: 1000, terminal: true, $$tlb: true, - compile: function(element, attr, linker) { - return function($scope, $element, $attr){ + link: function($scope, $element, $attr, ctrl, $transclude){ var expression = $attr.ngRepeat; var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/), trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn, @@ -18720,7 +18823,7 @@ // jshint bitwise: true if (!block.startNode) { - linker(childScope, function(clone) { + $transclude(childScope, function(clone) { clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' '); $animate.enter(clone, null, jqLite(previousNode)); previousNode = clone; @@ -18733,7 +18836,6 @@ } lastBlockMap = nextBlockMap; }); - }; } }; }]; @@ -19242,10 +19344,10 @@ transclude: 'element', priority: 800, require: '^ngSwitch', - compile: function(element, attrs, transclude) { - return function(scope, element, attr, ctrl) { + compile: function(element, attrs) { + return function(scope, element, attr, ctrl, $transclude) { ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []); - ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: transclude, element: element }); + ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element }); }; } }); @@ -19254,12 +19356,10 @@ transclude: 'element', priority: 800, require: '^ngSwitch', - compile: function(element, attrs, transclude) { - return function(scope, element, attr, ctrl) { - ctrl.cases['?'] = (ctrl.cases['?'] || []); - ctrl.cases['?'].push({ transclude: transclude, element: element }); - }; - } + link: function(scope, element, attr, ctrl, $transclude) { + ctrl.cases['?'] = (ctrl.cases['?'] || []); + ctrl.cases['?'].push({ transclude: $transclude, element: element }); + } }); /**
participants (1)
-
echatellier@users.nuiton.org