Skip to content

Commit

Permalink
Merge pull request #198 from Stabzs/master
Browse files Browse the repository at this point in the history
Added additional validation for directiveTemplate
  • Loading branch information
Stabzs committed Feb 18, 2016
2 parents b79e1f3 + ba9822e commit e3fe3c2
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 38 deletions.
21 changes: 13 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ AngularJS-Toaster
**AngularJS Toaster** is an AngularJS port of the **toastr** non-blocking notification jQuery library. It requires AngularJS v1.2.6 or higher and angular-animate for the CSS3 transformations.

[![Build Status](https://travis-ci.org/jirikavi/AngularJS-Toaster.svg)](https://travis-ci.org/jirikavi/AngularJS-Toaster)
[![Coverage Status](https://coveralls.io/repos/jirikavi/AngularJS-Toaster/badge.svg?branch=master&service=github&busted=1)](https://coveralls.io/github/jirikavi/AngularJS-Toaster?branch=master)
[![Coverage Status](https://coveralls.io/repos/jirikavi/AngularJS-Toaster/badge.svg?branch=master&service=github&busting=3)](https://coveralls.io/github/jirikavi/AngularJS-Toaster?branch=master)

### Current Version 1.1.0
### Current Version 1.2.0

## Angular Compatibility
AngularJS-Toaster requires AngularJS v1.2.6 or higher and specifically targets AngularJS, not Angular 2, although it could be used via ngUpgrade.
If you are looking for the Angular 2 port of AngularJS-Toaster, it is located [here](https://github.com/Stabzs/Angular2-Toaster).

## Demo
- Simple demo is at http://plnkr.co/edit/HKTC1a
Expand Down Expand Up @@ -129,8 +133,8 @@ There are four types of body renderings: trustedHtml', 'template', 'templateWith

- directive
- Will use the `toast.body` argument to represent the name of a directive that you want to render as the toast's body, else it will fallback to the template bound to the `'body-template': 'toasterBodyTmpl.html'` configuration option.
The directive name being passed to the `body` argument should be normalized as it exists in the markup,
not camelCased as it would appear in the directive declaration (`cool-directive-name` instead of `coolDirectiveName`).
The directive name being passed to the `body` argument should appear as it exists in the markup,
not camelCased as it would appear in the directive declaration (`cool-directive-name` instead of `coolDirectiveName`). The directive must be usable as an attribute.

```js
// The toast pop call, passing in a directive name to be rendered
Expand All @@ -149,7 +153,8 @@ There are four types of body renderings: trustedHtml', 'template', 'templateWith
};
}])
```
- Will use the `toast.directiveData` argument to accept data that will be bound to the directive's scope.
- Will use the `toast.directiveData` argument to accept data that will be bound to the directive's scope. The directive cannot use isolateScope and will
throw an exception if isolateScope is detected. All data must be passed via the directiveData argument.

```js
// The toast pop call, passing in a directive name to be rendered
Expand Down Expand Up @@ -275,7 +280,7 @@ If you do not want to use animations, you can safely remove the angular-animate.
### Common Issues
- Toaster always shows up as "info"
- Your `<toaster-container></toaster-container` might be placed inside of your routing directive.
- You have multiple `<toaster-container></toaster-container` elements without unqiue `toaster-id` configuration arguments.
- You have multiple `<toaster-container></toaster-container` elements without unique `toaster-id` configuration arguments.
- [$sce:itype] Attempted to trust a non-string value in a content requiring a string
- You have not specified: `bodyOutputType: 'trustedHtml'` when passing html as a body argument.
- My toasts do not show up when I pop them, but after I perform another action.
Expand All @@ -294,7 +299,7 @@ If you do not want to use animations, you can safely remove the angular-animate.
Inspired by http://codeseven.github.io/toastr/demo.html.

## Copyright
Copyright © 2013-2015 [Jiri Kavulak](https://twitter.com/jirikavi).
Copyright © 2013-2016 [Jiri Kavulak](https://twitter.com/jirikavi).

## License
AngularJS-Toaster is under MIT license - http://www.opensource.org/licenses/mit-license.php
AngularJS-Toaster is under MIT license - http://www.opensource.org/licenses/mit-license.php
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "AngularJS-Toaster",
"version": "1.1.0",
"version": "1.2.0",
"main": [
"toaster.js",
"toaster.css"
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "angularjs-toaster",
"version": "1.1.0",
"version": "1.2.0",
"description": "AngularJS Toaster is a customized version of toastr non-blocking notification javascript library",
"author": "Jiri Kavulak",
"license": "MIT",
Expand All @@ -14,11 +14,11 @@
"angular-animate": "~1.2.8",
"angular-mocks": "^1.4.7",
"jasmine-core": "^2.3.4",
"karma": "^0.13.14",
"karma-chrome-launcher": "^0.2.1",
"karma": "^0.13.21",
"karma-chrome-launcher": "^0.2.2",
"karma-coverage": "^0.5.3",
"karma-jasmine": "^0.3.6",
"coveralls": "^2.11.4"
"karma-jasmine": "^0.3.7",
"coveralls": "^2.11.6"
},
"jspm": {
"main": "toaster",
Expand Down
73 changes: 58 additions & 15 deletions test/directiveTemplateSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
'use strict';

describe('directiveTemplate', function () {
createDirectives();

var toaster, scope, $compile;

beforeEach(function () {
createDirectives();

// load dependencies
module('testApp');
module('toaster')
module('toaster');

// inject the toaster service
inject(function (_toaster_, _$rootScope_, _$compile_) {
Expand Down Expand Up @@ -62,20 +62,38 @@ describe('directiveTemplate', function () {
expect(container[0].innerText).toBe('Unrestricted Template');
});

it('should not bind Element-restricted templates', function () {
it('should not bind Element-only-restricted templates', function () {
var hasError = false;
var container = compileContainer();
pop({ type: 'info', body: 'element-template', bodyOutputType: 'directive' });

expect(container[0].innerText).toBe('');
expect(container[0].innerText).not.toBe('Element Template');

try {
pop({ type: 'info', body: 'element-template', bodyOutputType: 'directive' });
} catch(e) {
var message = 'Directives must be usable as attributes. ' +
'Add "A" to the restrict option (or remove the option entirely). Occurred for directive element-template.';

expect(e.message).toBe(message);
hasError = true;
}

expect(hasError).toBe(true);
});

it('should not bind Class-restricted templates', function () {
it('should not bind Class-only-restricted templates', function () {
var hasError = false;
var container = compileContainer();
pop({ type: 'info', body: 'class-template', bodyOutputType: 'directive' });

expect(container[0].innerText).toBe('');
expect(container[0].innerText).not.toBe('Class Template');

try {
pop({ type: 'info', body: 'class-template', bodyOutputType: 'directive' });
} catch(e) {
var message = 'Directives must be usable as attributes. ' +
'Add "A" to the restrict option (or remove the option entirely). Occurred for directive class-template.';

expect(e.message).toBe(message);
hasError = true;
}

expect(hasError).toBe(true);
});

it('should throw an error if directiveName argument is not passed via body', function () {
Expand Down Expand Up @@ -120,12 +138,34 @@ describe('directiveTemplate', function () {
try {
pop({ type: 'info', body: 'non-existent-directive', bodyOutputType: 'directive' });
} catch (e) {
expect(e.message).toBe('non-existent-directive could not be found.');
var message = 'non-existent-directive could not be found. ' +
'The name should appear as it exists in the markup,' +
' not camelCased as it would appear in the directive declaration,' +
' e.g. directive-name not directiveName.'

expect(e.message).toBe(message);
hasError = true;
}

expect(hasError).toBe(true);
});

it('should throw an error if the directive uses isolate scope', function () {
var hasError = false;
compileContainer();

try {
pop({ type: 'info', body: 'isolate-scope', bodyOutputType: 'directive' });
} catch (e) {
var message = 'Cannot use a directive with an isolated scope.' +
' The scope must be either true or falsy (e.g. false/null/undefined). Occurred for directive isolate-scope.';

expect(e.message).toBe(message)
hasError = true;
}

expect(hasError).toBe(true);
})


function compileContainer() {
Expand Down Expand Up @@ -165,6 +205,9 @@ describe('directiveTemplate', function () {
})
.directive('unrestrictedTemplate', function () {
return { template: 'Unrestricted Template' }
});
})
.directive('isolateScope', function () {
return { template: 'isolate scope template', scope: {}}
});
}
})
3 changes: 2 additions & 1 deletion toaster.css
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ button.toast-close-button {
#toast-container {
position: fixed;
z-index: 999999;
pointer-events: auto;
/*overrides*/

}
Expand Down Expand Up @@ -236,4 +237,4 @@ button.toast-close-button {
:not(.no-leave)#toast-container > div.ng-leave.ng-leave-active,
:not(.no-enter)#toast-container > div.ng-enter {
opacity: 0;
}
}
30 changes: 25 additions & 5 deletions toaster.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

/*
* AngularJS Toaster
* Version: 1.1.0
* Version: 1.2.0
*
* Copyright 2013-2016 Jiri Kavulak.
* All Rights Reserved.
Expand Down Expand Up @@ -200,11 +200,31 @@
if (angular.isUndefined(directiveName) || directiveName.length <= 0)
throw new Error('A valid directive name must be provided via the toast body argument when using bodyOutputType: directive');

var directiveExists = $injector.has(attrs.$normalize(directiveName) + 'Directive');
var directive;

try {
directive = $injector.get(attrs.$normalize(directiveName) + 'Directive');
} catch(e) {
throw new Error(directiveName + ' could not be found. ' +
'The name should appear as it exists in the markup, not camelCased as it would appear in the directive declaration,' +
' e.g. directive-name not directiveName.');
}

if (!directiveExists)
throw new Error(directiveName + ' could not be found.');

var directiveDetails = directive[0];

if (directiveDetails.scope !== true && directiveDetails.scope) {
throw new Error('Cannot use a directive with an isolated scope. ' +
'The scope must be either true or falsy (e.g. false/null/undefined). ' +
'Occurred for directive ' + directiveName + '.');
}

if (directiveDetails.restrict.indexOf('A') < 0) {
throw new Error('Directives must be usable as attributes. ' +
'Add "A" to the restrict option (or remove the option entirely). Occurred for directive ' +
directiveName + '.');
}

if (scope.directiveData)
scope.directiveData = angular.fromJson(scope.directiveData);

Expand All @@ -213,7 +233,7 @@
elm.append(template);
});
}
}
};
}])
.directive(
'toasterContainer', [
Expand Down
Loading

0 comments on commit e3fe3c2

Please sign in to comment.