'use strict'; /** * @ngdoc directive * @name ng.directive:ngHref * @restrict A * * @description * Using Angular markup like {{hash}} in an href attribute makes * the page open to a wrong URL, if the user clicks that link before * angular has a chance to replace the {{hash}} with actual URL, the * link will be broken and will most likely return a 404 error. * The `ngHref` directive solves this problem. * * The buggy way to write it: * <pre> * <a href="http://www.gravatar.com/avatar/{{hash}}"/> * </pre> * * The correct way to write it: * <pre> * <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/> * </pre> * * @element A * @param {template} ngHref any string which can contain `{{}}` markup. * * @example * This example uses `link` variable inside `href` attribute: <doc:example> <doc:source> <input ng-model="value" /><br /> <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br /> <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br /> <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br /> <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br /> <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br /> <a id="link-6" ng-href="{{value}}">link</a> (link, change location) </doc:source> <doc:scenario> it('should execute ng-click but not reload when href without value', function() { element('#link-1').click(); expect(input('value').val()).toEqual('1'); expect(element('#link-1').attr('href')).toBe(""); }); it('should execute ng-click but not reload when href empty string', function() { element('#link-2').click(); expect(input('value').val()).toEqual('2'); expect(element('#link-2').attr('href')).toBe(""); }); it('should execute ng-click and change url when ng-href specified', function() { expect(element('#link-3').attr('href')).toBe("/123"); element('#link-3').click(); expect(browser().window().path()).toEqual('/123'); }); it('should execute ng-click but not reload when href empty string and name specified', function() { element('#link-4').click(); expect(input('value').val()).toEqual('4'); expect(element('#link-4').attr('href')).toBe(''); }); it('should execute ng-click but not reload when no href but name specified', function() { element('#link-5').click(); expect(input('value').val()).toEqual('5'); expect(element('#link-5').attr('href')).toBe(undefined); }); it('should only change url when only ng-href', function() { input('value').enter('6'); expect(element('#link-6').attr('href')).toBe('6'); element('#link-6').click(); expect(browser().location().url()).toEqual('/6'); }); </doc:scenario> </doc:example> */ /** * @ngdoc directive * @name ng.directive:ngSrc * @restrict A * * @description * Using Angular markup like `{{hash}}` in a `src` attribute doesn't * work right: The browser will fetch from the URL with the literal * text `{{hash}}` until Angular replaces the expression inside * `{{hash}}`. The `ngSrc` directive solves this problem. * * The buggy way to write it: * <pre> * <img src="http://www.gravatar.com/avatar/{{hash}}"/> * </pre> * * The correct way to write it: * <pre> * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/> * </pre> * * @element IMG * @param {template} ngSrc any string which can contain `{{}}` markup. */ /** * @ngdoc directive * @name ng.directive:ngSrcset * @restrict A * * @description * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't * work right: The browser will fetch from the URL with the literal * text `{{hash}}` until Angular replaces the expression inside * `{{hash}}`. The `ngSrcset` directive solves this problem. * * The buggy way to write it: * <pre> * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/> * </pre> * * The correct way to write it: * <pre> * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/> * </pre> * * @element IMG * @param {template} ngSrcset any string which can contain `{{}}` markup. */ /** * @ngdoc directive * @name ng.directive:ngDisabled * @restrict A * * @description * * The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs: * <pre> * <div ng-init="scope = { isDisabled: false }"> * <button disabled="{{scope.isDisabled}}">Disabled</button> * </div> * </pre> * * The HTML specs do not require browsers to preserve the special attributes such as disabled. * (The presence of them means true and absence means false) * This prevents the angular compiler from correctly retrieving the binding expression. * To solve this problem, we introduce the `ngDisabled` directive. * * @example <doc:example> <doc:source> Click me to toggle: <input type="checkbox" ng-model="checked"><br/> <button ng-model="button" ng-disabled="checked">Button</button> </doc:source> <doc:scenario> it('should toggle button', function() { expect(element('.doc-example-live :button').prop('disabled')).toBeFalsy(); input('checked').check(); expect(element('.doc-example-live :button').prop('disabled')).toBeTruthy(); }); </doc:scenario> </doc:example> * * @element INPUT * @param {expression} ngDisabled Angular expression that will be evaluated. */ /** * @ngdoc directive * @name ng.directive:ngChecked * @restrict A * * @description * The HTML specs do not require browsers to preserve the special attributes such as checked. * (The presence of them means true and absence means false) * This prevents the angular compiler from correctly retrieving the binding expression. * To solve this problem, we introduce the `ngChecked` directive. * @example <doc:example> <doc:source> Check me to check both: <input type="checkbox" ng-model="master"><br/> <input id="checkSlave" type="checkbox" ng-checked="master"> </doc:source> <doc:scenario> it('should check both checkBoxes', function() { expect(element('.doc-example-live #checkSlave').prop('checked')).toBeFalsy(); input('master').check(); expect(element('.doc-example-live #checkSlave').prop('checked')).toBeTruthy(); }); </doc:scenario> </doc:example> * * @element INPUT * @param {expression} ngChecked Angular expression that will be evaluated. */ /** * @ngdoc directive * @name ng.directive:ngReadonly * @restrict A * * @description * The HTML specs do not require browsers to preserve the special attributes such as readonly. * (The presence of them means true and absence means false) * This prevents the angular compiler from correctly retrieving the binding expression. * To solve this problem, we introduce the `ngReadonly` directive. * @example <doc:example> <doc:source> Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/> <input type="text" ng-readonly="checked" value="I'm Angular"/> </doc:source> <doc:scenario> it('should toggle readonly attr', function() { expect(element('.doc-example-live :text').prop('readonly')).toBeFalsy(); input('checked').check(); expect(element('.doc-example-live :text').prop('readonly')).toBeTruthy(); }); </doc:scenario> </doc:example> * * @element INPUT * @param {string} expression Angular expression that will be evaluated. */ /** * @ngdoc directive * @name ng.directive:ngSelected * @restrict A * * @description * The HTML specs do not require browsers to preserve the special attributes such as selected. * (The presence of them means true and absence means false) * This prevents the angular compiler from correctly retrieving the binding expression. * To solve this problem, we introduced the `ngSelected` directive. * @example <doc:example> <doc:source> Check me to select: <input type="checkbox" ng-model="selected"><br/> <select> <option>Hello!</option> <option id="greet" ng-selected="selected">Greetings!</option> </select> </doc:source> <doc:scenario> it('should select Greetings!', function() { expect(element('.doc-example-live #greet').prop('selected')).toBeFalsy(); input('selected').check(); expect(element('.doc-example-live #greet').prop('selected')).toBeTruthy(); }); </doc:scenario> </doc:example> * * @element OPTION * @param {string} expression Angular expression that will be evaluated. */ /** * @ngdoc directive * @name ng.directive:ngOpen * @restrict A * * @description * The HTML specs do not require browsers to preserve the special attributes such as open. * (The presence of them means true and absence means false) * This prevents the angular compiler from correctly retrieving the binding expression. * To solve this problem, we introduce the `ngOpen` directive. * * @example <doc:example> <doc:source> Check me check multiple: <input type="checkbox" ng-model="open"><br/> <details id="details" ng-open="open"> <summary>Show/Hide me</summary> </details> </doc:source> <doc:scenario> it('should toggle open', function() { expect(element('#details').prop('open')).toBeFalsy(); input('open').check(); expect(element('#details').prop('open')).toBeTruthy(); }); </doc:scenario> </doc:example> * * @element DETAILS * @param {string} expression Angular expression that will be evaluated. */ var ngAttributeAliasDirectives = {}; // boolean attrs are evaluated forEach(BOOLEAN_ATTR, function(propName, attrName) { // binding to multiple is not supported if (propName == "multiple") return; var normalized = directiveNormalize('ng-' + attrName); ngAttributeAliasDirectives[normalized] = function() { return { priority: 100, compile: function() { return function(scope, element, attr) { scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) { attr.$set(attrName, !!value); }); }; } }; }; }); // ng-src, ng-srcset, ng-href are interpolated forEach(['src', 'srcset', 'href'], function(attrName) { var normalized = directiveNormalize('ng-' + attrName); ngAttributeAliasDirectives[normalized] = function() { return { priority: 99, // it needs to run after the attributes are interpolated link: function(scope, element, attr) { attr.$observe(normalized, function(value) { if (!value) return; attr.$set(attrName, value); // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need // to set the property as well to achieve the desired effect. // we use attr[attrName] value since $set can sanitize the url. if (msie) element.prop(attrName, attr[attrName]); }); } }; }; });