Skip to content

Commit

Permalink
fix(icon): stop breaking id references when caching icon ids (angular…
Browse files Browse the repository at this point in the history
…#11342)

<!-- 
Filling out this template is required! Do not delete it when submitting a Pull Request! Without this information, your Pull Request may be auto-closed.
-->
## PR Checklist
Please check that your PR fulfills the following requirements:
- [x] The commit message follows [our guidelines](https://github.com/angular/material/blob/master/.github/CONTRIBUTING.md#-commit-message-format)
- [x] Tests for the changes have been added or this is not a bug fix / enhancement
- [x] Docs have been added, updated, or were not required

## PR Type
What kind of change does this PR introduce?
<!-- Please check the one that applies to this PR using "x". -->
```
[x] Bugfix
[ ] Enhancement
[x] Documentation content changes
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Infrastructure changes
[ ] Other... Please describe:
```

## What is the current behavior?
SVGs with embedded `id`s can be broken when they are read out of the icon cache.

<!-- Please describe the current behavior that you are modifying and link to one or more relevant issues. -->
Issue Number: 
Fixes angular#8689

## What is the new behavior?
SVGs with embedded `id`s can be read out of the icon cache without breaking because the `id` references are now updated in addition to the `id`s themselves.

## Does this PR introduce a breaking change?
```
[ ] Yes
[x] No
```
<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->
<!-- Note that breaking changes are highly unlikely to get merged to master unless the validation is clear and the use case is critical. -->

## Other information
Thanks to @ystreibel for starting this work in angular#11315!
  • Loading branch information
Splaktar authored and marosoft committed Nov 11, 2018
1 parent 4dbf427 commit 8b47c53
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 105 deletions.
12 changes: 4 additions & 8 deletions src/components/icon/demoLoadSvgIconsFromUrl/script.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions src/components/icon/demoSvgIconSets/script.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@

angular.module('appSvgIconSets', ['ngMaterial'])
.controller('DemoCtrl', function($scope) {})
.config(['$mdIconProvider', function($mdIconProvider) {
.config(function($mdIconProvider) {
$mdIconProvider
.iconSet('social', 'img/icons/sets/social-icons.svg', 24)
.iconSet('symbol', 'img/icons/sets/symbol-icons.svg', 24)
.defaultIconSet('img/icons/sets/core-icons.svg', 24);
}]);
});
14 changes: 3 additions & 11 deletions src/components/icon/demoUsingTemplateRequest/script.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@

angular.module('appUsingTemplateCache', ['ngMaterial'])
.controller('DemoCtrl', function($scope) {})
.config(function($mdIconProvider) {

// Register icon IDs with sources. Future $mdIcon( <id> ) lookups
// will load by url and retrieve the data via the $templateRequest

$mdIconProvider
.iconSet('core', 'img/icons/sets/core-icons.svg',24)
.icon('social:cake', 'img/icons/cake.svg',24);

.iconSet('core', 'img/icons/sets/core-icons.svg', 24)
.icon('social:cake', 'img/icons/cake.svg', 24);
})
.run(function($templateRequest) {

var urls = [
'img/icons/sets/core-icons.svg',
'img/icons/cake.svg',
Expand All @@ -21,10 +16,7 @@ angular.module('appUsingTemplateCache', ['ngMaterial'])

// Pre-fetch icons sources by URL and cache in the $templateCache...
// subsequent $templateRequest calls will look there first.

angular.forEach(urls, function(url) {
$templateRequest(url);
});

})
;
});
24 changes: 24 additions & 0 deletions src/components/icon/icon.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,11 @@ describe('MdIcon service', function() {
$scope = $rootScope;

$templateCache.put('android.svg' , '<svg><g id="android"></g></svg>');
$templateCache.put('angular-logo.svg',
'<svg><g id="angular"></g><defs><filter id="shadow"></filter>' +
'<g id="bg" fill="#000000"><path d="M10 10"/></g></defs>' +
'<path filter="url(#shadow)"></path><use x="0" y="0" xlink:href="#bg"></use>' +
'</svg>');
$templateCache.put('social.svg' , '<svg><g id="s1"></g><g id="s2"></g></svg>');
$templateCache.put('symbol.svg' , '<svg><symbol id="s1"></symbol><symbol id="s2" viewBox="0 0 32 32"></symbol></svg>');
$templateCache.put('core.svg' , '<svg><g id="c1"></g><g id="c2" class="core"></g></svg>');
Expand Down Expand Up @@ -587,6 +592,25 @@ describe('MdIcon service', function() {

$scope.$digest();
});

it('should suffix duplicated ids and refs', function() {
// Just request the icon to be stored in the cache.
$mdIcon('angular-logo.svg');

$scope.$digest();

$mdIcon('angular-logo.svg').then(function(el) {
expect(el.querySelector('defs').firstChild.id).toMatch(/.+_cache\d+/g);
expect(el.querySelectorAll('path')[1].attributes.filter.value.split(/url\(#(.*)\)$/g)[1])
.toMatch(/.+_cache[0-9]+/g);
expect(el.querySelectorAll('path')[1].attributes.filter.value.split(/url\(#(.*)\)$/g)[1])
.toEqual(el.querySelector('defs').firstChild.id);
expect(el.querySelector('use').attributes['xlink:href'].value.split(/#(.*)/)[1]).toEqual(
el.querySelector('defs').children[1].id);
});

$scope.$digest();
});
});

describe('icon in a group is not found', function() {
Expand Down
117 changes: 58 additions & 59 deletions src/components/icon/js/iconDirective.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,11 @@ angular
* `md-icon` lets you consume an icon font by letting you reference specific icons in that font
* by name rather than character code.
*
* ### SVG
* For SVGs, the problem with using `<img>` or a CSS `background-image` is that you can't take
* advantage of some SVG features, such as styling specific parts of the icon with CSS or SVG
* animation.
*
* `md-icon` makes it easier to use SVG icons by *inlining* the SVG into an `<svg>` element in the
* document. The most straightforward way of referencing an SVG icon is via URL, just like a
* traditional `<img>`. `$mdIconProvider`, as a convenience, lets you _name_ an icon so you can
* reference it by name instead of URL throughout your templates.
*
* Additionally, you may not want to make separate HTTP requests for every icon, so you can bundle
* your SVG icons together and pre-load them with $mdIconProvider as an icon set. An icon set can
* also be given a name, which acts as a namespace for individual icons, so you can reference them
* like `"social:cake"`.
*
* When using SVGs, both external SVGs (via URLs) or sets of SVGs [from icon sets] can be
* easily loaded and used. When using font-icons, developers must follow three (3) simple steps:
* When using font-icons, developers must follow three (3) simple steps:
*
* <ol>
* <li>Load the font library. e.g.<br/>
* `<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
* rel="stylesheet">`
* `<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">`
* </li>
* <li>
* Use either (a) font-icon class names or (b) a fontset and a font ligature to render the font glyph by
Expand All @@ -63,26 +46,36 @@ angular
* </li>
* </ol>
*
* Full details for these steps can be found:
* Full details for these steps can be found in the
* <a href="http://google.github.io/material-design-icons/#icon-font-for-the-web" target="_blank">
* Material Design Icon font for the web docs</a>.
*
* <ul>
* <li>http://google.github.io/material-design-icons/</li>
* <li>http://google.github.io/material-design-icons/#icon-font-for-the-web</li>
* </ul>
* You can browse and search the Material Design icon style <code>.material-icons</code>
* in the <a href="https://material.io/tools/icons/" target="_blank">Material Design Icons tool</a>.
*
* The Material Design icon style <code>.material-icons</code> and the icon font references are published in
* Material Design Icons:
* ### SVG
* For SVGs, the problem with using `<img>` or a CSS `background-image` is that you can't take
* advantage of some SVG features, such as styling specific parts of the icon with CSS or SVG
* animation.
*
* <ul>
* <li>https://design.google.com/icons/</li>
* <li>https://design.google.com/icons/#ic_accessibility</li>
* </ul>
* `md-icon` makes it easier to use SVG icons by *inlining* the SVG into an `<svg>` element in the
* document. The most straightforward way of referencing an SVG icon is via URL, just like a
* traditional `<img>`. `$mdIconProvider`, as a convenience, lets you _name_ an icon so you can
* reference it by name instead of URL throughout your templates.
*
* Additionally, you may not want to make separate HTTP requests for every icon, so you can bundle
* your SVG icons together and pre-load them with `$mdIconProvider` as an icon set. An icon set can
* also be given a name, which acts as a namespace for individual icons, so you can reference them
* like `"social:cake"`.
*
* When using SVGs, both external SVGs (via URLs) or sets of SVGs (from icon sets) can be
* easily loaded and used.
*
* ### Localization
*
* Because an `md-icon` element's text content is not intended to be translated, it is recommended to declare the text
* content for an `md-icon` element in its start tag. Instead of using the HTML text content, consider using `ng-bind`
* with a scope variable or literal string.
* Because an `md-icon` element's text content is not intended to be translated, it is recommended
* to declare the text content for an `md-icon` element in its start tag. Instead of using the HTML
* text content, consider using `ng-bind` with a scope variable or literal string.
*
* Examples:
*
Expand All @@ -91,20 +84,25 @@ angular
* <li>`<md-icon ng-bind="'menu'"></md-icon>`
* </ul>
*
* <h2 id="material_design_icons">Material Design Icons</h2>
* Using the Material Design Icon-Selector, developers can easily and quickly search for a Material Design font-icon and
* determine its textual name and character reference code. Click on any icon to see the slide-up information
* panel with details regarding a SVG download or information on the font-icon usage.
* <h2 id="material_design_icons">Material Design Icons tool</h2>
* Using the Material Design Icons tool, developers can easily and quickly search for a specific
* open source Material Design icon. The search is in the top left. Below search, you can select
* from the new icon themes or filter by icon category.
*
* <a href="https://material.io/tools/icons/?icon=accessibility&style=baseline" target="_blank" style="border-bottom:none;">
* <img src="https://cloud.githubusercontent.com/assets/210413/7902490/fe8dd14c-0780-11e5-98fb-c821cc6475e6.png"
* aria-label="Material Design Icon-Selector" style="max-width:75%;padding-left:10%">
* <a href="https://material.io/tools/icons/" target="_blank" style="border-bottom:none;">
* <img src="https://user-images.githubusercontent.com/3506071/41942584-ef0695d0-796d-11e8-9436-44f25023a111.png"
* aria-label="Material Design Icons tool" style="max-width:95%">
* </a>
*
* <span class="image_caption">
* Click on the image above to link to the
* <a href="https://design.google.com/icons/#ic_accessibility" target="_blank">Material Design Icon-Selector</a>.
* </span>
* <div class="md-caption" style="text-align: center; margin-bottom: 24px">
* Click on the image above to open the
* <a href="https://material.io/tools/icons/" target="_blank">Material Design Icons tool</a>.
* </div>
*
* Click on any icon, then click on the "Selected Icon" chevron to see the slide-up
* information panel with details regarding a SVG download and information on the font-icon's
* textual name. This panel also allows you to select a black on transparent or white on transparent
* icon and to change the icon size. These settings only affect the downloaded icons.
*
* @param {string} md-font-icon String name of CSS icon associated with the font-face will be used
* to render the icon. Requires the fonts and the named CSS styles to be preloaded.
Expand All @@ -128,34 +126,35 @@ angular
* When using SVGs:
* <hljs lang="html">
*
* <!-- Icon ID; may contain optional icon set prefix; icons must registered using $mdIconProvider -->
* <md-icon md-svg-icon="social:android" aria-label="android " ></md-icon>
*<!-- Icon ID; may contain optional icon set prefix.
* Icons must be registered using $mdIconProvider. -->
*<md-icon md-svg-icon="social:android" aria-label="android " ></md-icon>
*
* <!-- Icon urls; may be preloaded in templateCache -->
* <md-icon md-svg-src="/android.svg" aria-label="android " ></md-icon>
* <md-icon md-svg-src="{{ getAndroid() }}" aria-label="android " ></md-icon>
*<!-- Icon urls; may be preloaded in templateCache -->
*<md-icon md-svg-src="/android.svg" aria-label="android " ></md-icon>
*<md-icon md-svg-src="{{ getAndroid() }}" aria-label="android " ></md-icon>
*
* </hljs>
*
* Use the <code>$mdIconProvider</code> to configure your application with
* svg iconsets.
* SVG icon sets.
*
* <hljs lang="js">
* angular.module('appSvgIconSets', ['ngMaterial'])
* .controller('DemoCtrl', function($scope) {})
* .config(function($mdIconProvider) {
* $mdIconProvider
* .iconSet('social', 'img/icons/sets/social-icons.svg', 24)
* .defaultIconSet('img/icons/sets/core-icons.svg', 24);
* });
* angular.module('appSvgIconSets', ['ngMaterial'])
* .controller('DemoCtrl', function($scope) {})
* .config(function($mdIconProvider) {
* $mdIconProvider
* .iconSet('social', 'img/icons/sets/social-icons.svg', 24)
* .defaultIconSet('img/icons/sets/core-icons.svg', 24);
* });
* </hljs>
*
*
* When using Font Icons with classnames:
* <hljs lang="html">
*
* <md-icon md-font-icon="android" aria-label="android" ></md-icon>
* <md-icon class="icon_home" aria-label="Home" ></md-icon>
* <md-icon md-font-icon="android" aria-label="android" ></md-icon>
* <md-icon class="icon_home" aria-label="Home"></md-icon>
*
* </hljs>
*
Expand Down

0 comments on commit 8b47c53

Please sign in to comment.