mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-22 17:40:22 +00:00
Closes# 850 fixed an issue where ng-href would not copy its content into href if it did not contain binding.
324 lines
11 KiB
JavaScript
324 lines
11 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* @ngdoc directive
|
|
* @name angular.module.ng.$compileProvider.directive.ng-href
|
|
* @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 `ng-href` solves this problem by placing the `href` in the
|
|
* `ng-` namespace.
|
|
*
|
|
* 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} ng-href 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'}}" ng-ext-link>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}}" ng-ext-link>link</a> (link, change hash)
|
|
</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("");
|
|
});
|
|
|
|
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().window().path()).toEqual('/6');
|
|
});
|
|
</doc:scenario>
|
|
</doc:example>
|
|
*/
|
|
|
|
/**
|
|
* @ngdoc directive
|
|
* @name angular.module.ng.$compileProvider.directive.ng-src
|
|
* @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 `ng-src` attribute solves this problem by placing
|
|
* the `src` attribute in the `ng-` namespace.
|
|
*
|
|
* 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} ng-src any string which can contain `{{}}` markup.
|
|
*/
|
|
|
|
/**
|
|
* @ngdoc directive
|
|
* @name angular.module.ng.$compileProvider.directive.ng-disabled
|
|
* @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 ng-disabled.
|
|
*
|
|
* @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 {string} expression Angular expression that will be evaluated.
|
|
*/
|
|
|
|
|
|
/**
|
|
* @ngdoc directive
|
|
* @name angular.module.ng.$compileProvider.directive.ng-checked
|
|
* @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 ng-checked.
|
|
* @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 {string} expression Angular expression that will be evaluated.
|
|
*/
|
|
|
|
|
|
/**
|
|
* @ngdoc directive
|
|
* @name angular.module.ng.$compileProvider.directive.ng-multiple
|
|
* @restrict A
|
|
*
|
|
* @description
|
|
* The HTML specs do not require browsers to preserve the special attributes such as multiple.
|
|
* (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 ng-multiple.
|
|
*
|
|
* @example
|
|
<doc:example>
|
|
<doc:source>
|
|
Check me check multiple: <input type="checkbox" ng-model="checked"><br/>
|
|
<select id="select" ng-multiple="checked">
|
|
<option>Misko</option>
|
|
<option>Igor</option>
|
|
<option>Vojta</option>
|
|
<option>Di</option>
|
|
</select>
|
|
</doc:source>
|
|
<doc:scenario>
|
|
it('should toggle multiple', function() {
|
|
expect(element('.doc-example-live #select').prop('multiple')).toBeFalsy();
|
|
input('checked').check();
|
|
expect(element('.doc-example-live #select').prop('multiple')).toBeTruthy();
|
|
});
|
|
</doc:scenario>
|
|
</doc:example>
|
|
*
|
|
* @element SELECT
|
|
* @param {string} expression Angular expression that will be evaluated.
|
|
*/
|
|
|
|
|
|
/**
|
|
* @ngdoc directive
|
|
* @name angular.module.ng.$compileProvider.directive.ng-readonly
|
|
* @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 ng-readonly.
|
|
* @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 angular.module.ng.$compileProvider.directive.ng-selected
|
|
* @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 introduce ng-selected.
|
|
* @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.
|
|
*/
|
|
|
|
|
|
var ngAttributeAliasDirectives = {};
|
|
|
|
|
|
// boolean attrs are evaluated
|
|
forEach(BOOLEAN_ATTR, function(propName, attrName) {
|
|
var normalized = directiveNormalize('ng-' + attrName);
|
|
ngAttributeAliasDirectives[normalized] = function() {
|
|
return {
|
|
priority: 100,
|
|
compile: function(tpl, attr) {
|
|
return function(scope, element, attr) {
|
|
attr.$$observers[attrName] = [];
|
|
scope.$watch(attr[normalized], function(value) {
|
|
attr.$set(attrName, value);
|
|
});
|
|
};
|
|
}
|
|
};
|
|
};
|
|
});
|
|
|
|
|
|
// ng-src, ng-href are interpolated
|
|
forEach(['src', 'href'], function(attrName) {
|
|
var normalized = directiveNormalize('ng-' + attrName);
|
|
ngAttributeAliasDirectives[normalized] = function() {
|
|
return {
|
|
priority: 99, // it needs to run after the attributes are interpolated
|
|
compile: function(tpl, attr) {
|
|
return function(scope, element, attr) {
|
|
var value = attr[normalized];
|
|
if (value == undefined) {
|
|
// undefined value means that the directive is being interpolated
|
|
// so just register observer
|
|
attr.$$observers[attrName] = [];
|
|
attr.$observe(normalized, function(value) {
|
|
attr.$set(attrName, value);
|
|
});
|
|
} else {
|
|
// value present means that no interpolation, so copy to native attribute.
|
|
attr.$set(attrName, value);
|
|
}
|
|
};
|
|
}
|
|
};
|
|
};
|
|
});
|