doc(fixes): to better support ng-directive notation

This commit is contained in:
Misko Hevery 2012-03-09 15:12:48 -08:00
parent 488a03631e
commit 3e5377f4f3
12 changed files with 249 additions and 60 deletions

162
docs/content/guide/ie.ngdoc Normal file
View file

@ -0,0 +1,162 @@
@ngdoc overview
@name Developer Guide: Internet Explorer Compatibility
@description
# Overview
This document describes the Internet Explorer (IE) idiosyncrasies when dealing with custom HTML
attributes and tags. Read this document if you are planning on deploying your angular application
on IE v8.0 or earlier.
# Short Version
To make your angular application work on IE please make sure that:
1. you **do not** use custom element tags such as `<ng:view>` (use the attribute version `<div
ng-view>` instead), or
2. if you **do use** custom element tags, then you must take these steps to make IE happy:
<pre>
<html xmlns:ng="http://angularjs.org">
<head>
<!--[if lte IE 8]>
<script>
document.createElement('ng-include');
document.createElement('ng-pluralize');
document.createElement('ng-view');
// Optionally these for CSS
document.createElement('ng:include');
document.createElement('ng:pluralize');
document.createElement('ng:view');
</script>
<![endif]-->
</head>
<body>
...
</body>
</html>
</pre>
The **important** parts are:
* `xmlns:ng` - *namespace* - you need one namespace for each custom tay you are planning on
using.
* `document.createElement(yourTagName)` - *creation of custom tag names* - Since this is an
issue only for older version of IE you need to load it conditionally. For each tag which does
not have namespace and which is not defined in HTML you need to pre-declare it to make IE
happy.
# Long Version
IE has an issues with element tag names which are not standard HTML tag names. These fall into two
categories, and each category has its own fix.
* If the tag name starts with `my:` prefix than it is considered an XML namespace and must
have corresponding namespace declaration on `<html xmlns:my="ignored">`
* If the tag has no `:` but it is not a standard HTML tag, then it must be pre-created using
`document.createElement('my-tag')`
* If you have are planning on styling the custom tag with CSS selectors, then it must be
pre-created using `document.createElement('my-tag')` regardless of XML namespace.
## The Good News
The good news is that these restrictions only apply to element tag names, and not to element
attribute names. So this requires no special handling in IE: `<div my-tag your:tag></div>`.
## What happens if I fail to do this?
Suppose you have HTML with unknown tag `mytag` (this could also be `my:tag` or `my-tag` with same
result):
<pre>
<html>
<body>
<mytag>some text</mytag>
</body>
</html>
</pre>
It should pares into the following DOM:
<pre>
#document
+- HTML
+- BODY
+- mytag
+- #text: some text
</pre>
The expected behavior is that the `BODY` element has a child element `mytag`, which in turn has
the text `some text`.
But this is not what IE does (if the above fixes are not included):
<pre>
#document
+- HTML
+- BODY
+- mytag
+- #text: some text
+- /mytag
</pre>
In IE, the behavior is that the `BODY` element has three children:
1. A self closing `mytag`. Example of self closing tag is `<br/>`. The trailing `/` is optional,
but the `<br>` tag is not allowed to have any children, and browsers consider `<br>some
text</br>` as three siblings not a `<br>` with `some text` as child.
2. A text node with `some text`. This should have been a child of `mytag` above, not a sibling.
3. A corrupt self closing `/mytag`. This is corrupt since element names are not allowed to have
the `/` character. Furthermore this closing element should not be part of the DOM since it is
only used to delimitate the structure of the DOM.
## CSS Styling of Custom Tag Names
The to make CSS selector work with custom elements the custom element name must be shived with the
`document.createElement('my-tag')` regardless of XML namespace.
<pre>
<html xmlns:ng="needed for ng: namespace">
<head>
<!--[if lte IE 8]>
<script>
// needed to make ng-include parse properly
document.createElement('ng-include');
// needed to enable CSS reference
document.createElement('ng:view');
</script>
<![endif]-->
<style>
ng\\:view {
display: block;
border: 1px solid red;
}
ng-include {
display: block;
border: 1px solid blue;
}
</style>
</head>
<body>
<ng:view></ng:view>
<ng-include></ng-include>
...
</body>
</html>
</pre>

View file

@ -19,7 +19,8 @@ function DOM() {
var INLINE_TAGS = {
i: true,
b: true
b: true,
a: true
};
DOM.prototype = {

View file

@ -367,18 +367,14 @@ Doc.prototype = {
dom.h('Usage', function() {
var restrict = self.restrict || 'AC';
if (restrict.match(/E/)) {
dom.text('as element');
dom.text('as element (see ');
dom.tag('a', {href:'guide/ie'}, 'IE restrictions');
dom.text(')');
dom.code(function() {
dom.text('<');
dom.text(self.shortName);
(self.param||[]).forEach(function(param){
dom.text('\n ');
dom.text(param.optional ? ' [' : ' ');
dom.text(param.name);
dom.text(BOOLEAN_ATTR[param.name] ? '' : '="..."');
dom.text(param.optional ? ']' : '');
});
dom.text('></');
renderParams('\n ', '="', '"');
dom.text('>\n</');
dom.text(self.shortName);
dom.text('>');
});
@ -389,9 +385,7 @@ Doc.prototype = {
dom.code(function() {
dom.text('<' + element + ' ');
dom.text(self.shortName);
if (self.param.length) {
dom.text('="' + self.param[0].name + '"');
}
renderParams('\n ', '="', '"', true);
dom.text('>\n ...\n');
dom.text('</' + element + '>');
});
@ -402,9 +396,7 @@ Doc.prototype = {
dom.code(function() {
dom.text('<' + element + ' class="');
dom.text(self.shortName);
if (self.param.length) {
dom.text(': ' + self.param[0].name + ';');
}
renderParams(' ', ': ', ';', true);
dom.text('">\n ...\n');
dom.text('</' + element + '>');
});
@ -414,6 +406,27 @@ Doc.prototype = {
});
self.method_properties_events(dom);
function renderParams(prefix, infix, suffix, skipSelf) {
(self.param||[]).forEach(function(param) {
var skip = skipSelf && (param.name == self.shortName || param.name.indexOf(self.shortName + '|') == 0);
if (!skip) {
dom.text(prefix);
dom.text(param.optional ? '[' : '');
var parts = param.name.split('|');
dom.text(parts[skipSelf ? 0 : 1] || parts[0]);
}
if (BOOLEAN_ATTR[param.name]) {
dom.text(param.optional ? ']' : '');
} else {
dom.text(BOOLEAN_ATTR[param.name] ? '' : infix );
dom.text(('{' + param.type + '}').replace(/^\{\'(.*)\'\}$/, '$1'));
dom.text(param.optional ? ']' : '');
dom.text(suffix);
}
});
}
},
html_usage_filter: function(dom){
@ -455,7 +468,7 @@ Doc.prototype = {
dom.text('\n ');
dom.text(param.optional ? ' [' : ' ');
dom.text(param.name);
dom.text(BOOLEAN_ATTR[param.name] ? '' : '="..."');
dom.text(BOOLEAN_ATTR[param.name] ? '' : '="{' + param.type + '}"');
dom.text(param.optional ? ']' : '');
});
dom.text('>');

View file

@ -818,7 +818,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
* @name angular.module.ng.$compileProvider.directive.ng-app
*
* @element ANY
* @param {angular.Module} module on optional application
* @param {angular.Module} ng-app on optional application
* {@link angular.module module} name to load.
*
* @description

View file

@ -3,6 +3,7 @@
/**
* @ngdoc directive
* @name angular.module.ng.$compileProvider.directive.ng-href
* @restrict A
*
* @description
* Using <angular/> markup like {{hash}} in an href attribute makes
@ -22,8 +23,8 @@
* <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
* </pre>
*
* @element ANY
* @param {template} template any string which can contain `{{}}` markup.
* @element A
* @param {template} ng-href any string which can contain `{{}}` markup.
*
* @example
* This example uses `link` variable inside `href` attribute:
@ -83,6 +84,7 @@
/**
* @ngdoc directive
* @name angular.module.ng.$compileProvider.directive.ng-src
* @restrict A
*
* @description
* Using <angular/> markup like `{{hash}}` in a `src` attribute doesn't
@ -101,13 +103,14 @@
* <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
* </pre>
*
* @element ANY
* @param {template} template any string which can contain `{{}}` markup.
* @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
*
@ -138,14 +141,15 @@
</doc:scenario>
</doc:example>
*
* @element ANY
* @param {template} template any string which can contain '{{}}' markup.
* @element INPUT
* @param {template} ng-disabled any string which can contain '{{}}' markup.
*/
/**
* @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.
@ -167,14 +171,15 @@
</doc:scenario>
</doc:example>
*
* @element ANY
* @param {template} template any string which can contain '{{}}' markup.
* @element INPUT
* @param {template} ng-checked any string which can contain '{{}}' markup.
*/
/**
* @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.
@ -202,14 +207,15 @@
</doc:scenario>
</doc:example>
*
* @element ANY
* @param {template} template any string which can contain '{{}}' markup.
* @element SELECT
* @param {template} ng-multiple any string which can contain '{{}}' markup.
*/
/**
* @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.
@ -231,41 +237,42 @@
</doc:scenario>
</doc:example>
*
* @element ANY
* @param {template} template any string which can contain '{{}}' markup.
* @element INPUT
* @param {template} ng-readonly any string which can contain '{{}}' markup.
*/
/**
* @ngdoc directive
* @name angular.module.ng.$compileProvider.directive.ng-selected
*
* @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="checked"><br/>
<select>
<option>Hello!</option>
<option id="greet" ng-selected="{{checked}}">Greetings!</option>
</select>
</doc:source>
<doc:scenario>
it('should select Greetings!', function() {
expect(element('.doc-example-live #greet').prop('selected')).toBeFalsy();
input('checked').check();
expect(element('.doc-example-live #greet').prop('selected')).toBeTruthy();
});
</doc:scenario>
</doc:example>
* @element ANY
* @param {template} template any string which can contain '{{}}' markup.
*/
* @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="checked"><br/>
<select>
<option>Hello!</option>
<option id="greet" ng-selected="{{checked}}">Greetings!</option>
</select>
</doc:source>
<doc:scenario>
it('should select Greetings!', function() {
expect(element('.doc-example-live #greet').prop('selected')).toBeFalsy();
input('checked').check();
expect(element('.doc-example-live #greet').prop('selected')).toBeTruthy();
});
</doc:scenario>
</doc:example>
* @element OPTION
* @param {template} ng-selected any string which can contain '{{}}' markup.
*/
function ngAttributeAliasDirective(propName, attrName) {
ngAttributeAliasDirectives[directiveNormalize('ng-' + attrName)] = valueFn(

View file

@ -105,6 +105,7 @@ function FormController($scope, name) {
/**
* @ngdoc directive
* @name angular.module.ng.$compileProvider.directive.form
* @restrict EA
*
* @scope
* @description

View file

@ -616,6 +616,7 @@ function checkboxInputType(scope, element, attr, ctrl) {
/**
* @ngdoc directive
* @name angular.module.ng.$compileProvider.directive.input
* @restrict E
*
* @description
* HTML input element widget with angular data-binding. Input widget follows HTML5 input types
@ -916,6 +917,7 @@ var ngModelDirective = [function() {
/**
* @ngdoc directive
* @name angular.module.ng.$compileProvider.directive.ng-change
* @restrict E
*
* @description
* Evaluate given expression when user changes the input.

View file

@ -158,6 +158,7 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
/**
* @ngdoc directive
* @name angular.module.ng.$compileProvider.directive.ng-bind-attr
* @restrict A
*
* @description
* The `ng-bind-attr` attribute specifies that a

View file

@ -15,7 +15,7 @@
* <any ng-switch-default>...</any>
*
* @scope
* @param {*} on expression to match against <tt>ng-switch-when</tt>.
* @param {*} ng-switch|on expression to match against <tt>ng-switch-when</tt>.
* @paramDescription
* On child elments add:
*

View file

@ -9,6 +9,7 @@
* template can be used by `ng-include`, `ng-view` or directive templates.
*
* @restrict E
* @param {'text/ng-template'} type must be set to `'text/ng-template'`
*
* @example
<doc:example>

View file

@ -3,6 +3,7 @@
/**
* @ngdoc directive
* @name angular.module.ng.$compileProvider.directive.select
* @restrict E
*
* @description
* HTML `SELECT` element with angular data-binding.

View file