Remove Node modules from source control (#9963)
This commit is contained in:
parent
f20cdd6d2a
commit
beaf8d0348
2754 changed files with 1541 additions and 1236944 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -68,12 +68,6 @@ target
|
||||||
#############
|
#############
|
||||||
*dependency-reduced-pom.xml
|
*dependency-reduced-pom.xml
|
||||||
|
|
||||||
# nodejs #
|
|
||||||
##########
|
|
||||||
# KEYCLOAK-5391: We will re-exclude node_modules when node_modules handling is worked out.
|
|
||||||
# For now, we keep our js libraries checked into GitHub, so we don't ignore.
|
|
||||||
#node_modules
|
|
||||||
|
|
||||||
# testsuite #
|
# testsuite #
|
||||||
#############
|
#############
|
||||||
*offline-token.txt
|
*offline-token.txt
|
||||||
|
|
1
themes/.gitignore
vendored
1
themes/.gitignore
vendored
|
@ -1,2 +1,3 @@
|
||||||
node
|
node
|
||||||
|
node_modules
|
||||||
web_modules
|
web_modules
|
||||||
|
|
|
@ -1,26 +1,30 @@
|
||||||
## Updating dependencies for login, admin console, and old account console
|
# Updating dependencies
|
||||||
|
|
||||||
Edit `src/main/package.json` to update the dependency versions. Then run the following commands to download the new dependencies:
|
The dependencies will be downloaded at build time, based on the contents of `package-lock.json`. You should verify the new set of packages don't break anything before committing the new `package-lock.json`.
|
||||||
|
|
||||||
cd themes
|
## For login, admin console, and old account console
|
||||||
mvn clean install -Pnpm-update
|
|
||||||
|
|
||||||
The above will download the full NPM dependencies to `src/main/resources/theme/keycloak/common/resources/node_modules`. The main purpose of this directory is that we have the full source code available for dependencies in the future. This will be removed in the future as the internal build systems will take care of this.
|
```bash
|
||||||
|
cd src/main/resources/theme/keycloak/common/resources
|
||||||
Before committing changes review changes in `src/main/resources/theme/keycloak/common/resources/node_modules` making sure that it hasn't added new unused dependencies (transitive dependencies) and added any files that are not needed in the distribution (this is importat as the full node_modules downloaded are 176M while the filtered dependencies are 42M).
|
npm install some-package-name@version
|
||||||
|
|
||||||
|
|
||||||
## Updating dependencies for the new account console
|
|
||||||
|
|
||||||
The node dependencies will be downloaded at build time, based on the content of `package-lock.json`. To update `package-lock.json`:
|
|
||||||
|
|
||||||
cd src/main/resources/theme/keycloak.v2/account/resources/
|
|
||||||
npm install
|
|
||||||
git add package-lock.json
|
git add package-lock.json
|
||||||
cd -
|
cd -
|
||||||
|
```
|
||||||
|
|
||||||
You should verify the new set of packages don't break anything before commiting the new `package-lock.json`. Do not commit the `node_modules` directory for the new account console.
|
## For the new account console
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd src/main/resources/theme/keycloak.v2/account/resources
|
||||||
|
npm install some-package-name@version
|
||||||
|
git add package-lock.json
|
||||||
|
cd -
|
||||||
|
```
|
||||||
|
|
||||||
## License Information
|
## License Information
|
||||||
|
|
||||||
Make sure to enter license information for new dependencies, as specified in `docs/dependency-license-information.md`. Javascript dependencies are included as `other` elements.
|
Make sure to enter license information for new dependencies, as specified in `docs/dependency-license-information.md`. Javascript dependencies are included as `other` elements.
|
||||||
|
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
|
||||||
|
You can use `npm outdated --latest` in the same directory where the `package.json` file resides to see which dependencies are outdated
|
||||||
|
|
138
themes/pom.xml
138
themes/pom.xml
|
@ -19,19 +19,6 @@
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-clean-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<filesets>
|
|
||||||
<fileset>
|
|
||||||
<directory>${dir.common}/web_modules</directory>
|
|
||||||
</fileset>
|
|
||||||
</filesets>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
<resource>
|
<resource>
|
||||||
<directory>src/main/resources</directory>
|
<directory>src/main/resources</directory>
|
||||||
|
@ -151,6 +138,59 @@
|
||||||
</build>
|
</build>
|
||||||
</profile>
|
</profile>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<id>common</id>
|
||||||
|
<activation>
|
||||||
|
<property>
|
||||||
|
<name>!skipCommon</name>
|
||||||
|
</property>
|
||||||
|
</activation>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-clean-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<filesets>
|
||||||
|
<fileset>
|
||||||
|
<directory>${dir.common}/web_modules</directory>
|
||||||
|
</fileset>
|
||||||
|
</filesets>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.github.eirslett</groupId>
|
||||||
|
<artifactId>frontend-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<!-- Download NPM tools -->
|
||||||
|
<execution>
|
||||||
|
<id>setup-node</id>
|
||||||
|
<goals>
|
||||||
|
<goal>install-node-and-npm</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>initialize</phase>
|
||||||
|
</execution>
|
||||||
|
<!-- Download NPM packages -->
|
||||||
|
<execution>
|
||||||
|
<id>npm-install-common</id>
|
||||||
|
<phase>initialize</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>npm</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<workingDirectory>${dir.common}</workingDirectory>
|
||||||
|
<arguments>${args.npm.install}</arguments>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<nodeVersion>${node.version}</nodeVersion>
|
||||||
|
<installDirectory>${project.basedir}</installDirectory>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
|
||||||
<profile>
|
<profile>
|
||||||
<id>admin-preview</id>
|
<id>admin-preview</id>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -225,78 +265,6 @@
|
||||||
</resources>
|
</resources>
|
||||||
</build>
|
</build>
|
||||||
</profile>
|
</profile>
|
||||||
|
|
||||||
<profile>
|
|
||||||
<id>npm-update</id>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<!-- Download packages -->
|
|
||||||
<plugin>
|
|
||||||
<groupId>com.github.eirslett</groupId>
|
|
||||||
<artifactId>frontend-maven-plugin</artifactId>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>npm-install</id>
|
|
||||||
<phase>generate-resources</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>npm</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<workingDirectory>${dir.common}</workingDirectory>
|
|
||||||
<arguments>install -P -E --no-optional --ignore-scripts --no-bin-links --no-shrinkwrap --no-package-lock</arguments>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<!-- Clean downloaded packages from NPM -->
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-clean-plugin</artifactId>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>clean-all</id>
|
|
||||||
<phase>initialize</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>clean</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<filesets>
|
|
||||||
<fileset>
|
|
||||||
<directory>${dir.common}/node_modules</directory>
|
|
||||||
</fileset>
|
|
||||||
</filesets>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>clean-downloaded</id>
|
|
||||||
<phase>generate-resources</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>clean</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<filesets>
|
|
||||||
<fileset>
|
|
||||||
<directory>${dir.common}/node_modules/angular-translate/node_modules/</directory>
|
|
||||||
</fileset>
|
|
||||||
<fileset>
|
|
||||||
<directory>${dir.common}/node_modules/patternfly/node_modules/</directory>
|
|
||||||
</fileset>
|
|
||||||
<fileset>
|
|
||||||
<directory>${dir.common}/node_modules/rcue/node_modules/</directory>
|
|
||||||
</fileset>
|
|
||||||
<fileset>
|
|
||||||
<directory>${dir.common}/node_modules/minimist</directory>
|
|
||||||
</fileset>
|
|
||||||
<fileset>
|
|
||||||
<directory>${dir.common}/node_modules/mkdirp</directory>
|
|
||||||
</fileset>
|
|
||||||
</filesets>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
</profiles>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
# Do not commit, installed at compile time
|
|
||||||
node_modules
|
|
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2016 Angular
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
|
@ -1,68 +0,0 @@
|
||||||
# packaged angular-cookies
|
|
||||||
|
|
||||||
This repo is for distribution on `npm` and `bower`. The source for this module is in the
|
|
||||||
[main AngularJS repo](https://github.com/angular/angular.js/tree/master/src/ngCookies).
|
|
||||||
Please file issues and pull requests against that repo.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
You can install this package either with `npm` or with `bower`.
|
|
||||||
|
|
||||||
### npm
|
|
||||||
|
|
||||||
```shell
|
|
||||||
npm install angular-cookies
|
|
||||||
```
|
|
||||||
|
|
||||||
Then add `ngCookies` as a dependency for your app:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
angular.module('myApp', [require('angular-cookies')]);
|
|
||||||
```
|
|
||||||
|
|
||||||
### bower
|
|
||||||
|
|
||||||
```shell
|
|
||||||
bower install angular-cookies
|
|
||||||
```
|
|
||||||
|
|
||||||
Add a `<script>` to your `index.html`:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<script src="/bower_components/angular-cookies/angular-cookies.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
Then add `ngCookies` as a dependency for your app:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
angular.module('myApp', ['ngCookies']);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
Documentation is available on the
|
|
||||||
[AngularJS docs site](http://docs.angularjs.org/api/ngCookies).
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
The MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
|
@ -1,253 +0,0 @@
|
||||||
/**
|
|
||||||
* @license AngularJS v1.8.0
|
|
||||||
* (c) 2010-2020 Google, Inc. http://angularjs.org
|
|
||||||
* License: MIT
|
|
||||||
*/
|
|
||||||
(function(window, angular) {'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc module
|
|
||||||
* @name ngCookies
|
|
||||||
* @description
|
|
||||||
*
|
|
||||||
* The `ngCookies` module provides a convenient wrapper for reading and writing browser cookies.
|
|
||||||
*
|
|
||||||
* See {@link ngCookies.$cookies `$cookies`} for usage.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
angular.module('ngCookies', ['ng']).
|
|
||||||
info({ angularVersion: '1.8.0' }).
|
|
||||||
/**
|
|
||||||
* @ngdoc provider
|
|
||||||
* @name $cookiesProvider
|
|
||||||
* @description
|
|
||||||
* Use `$cookiesProvider` to change the default behavior of the {@link ngCookies.$cookies $cookies} service.
|
|
||||||
* */
|
|
||||||
provider('$cookies', [/** @this */function $CookiesProvider() {
|
|
||||||
/**
|
|
||||||
* @ngdoc property
|
|
||||||
* @name $cookiesProvider#defaults
|
|
||||||
* @description
|
|
||||||
*
|
|
||||||
* Object containing default options to pass when setting cookies.
|
|
||||||
*
|
|
||||||
* The object may have following properties:
|
|
||||||
*
|
|
||||||
* - **path** - `{string}` - The cookie will be available only for this path and its
|
|
||||||
* sub-paths. By default, this is the URL that appears in your `<base>` tag.
|
|
||||||
* - **domain** - `{string}` - The cookie will be available only for this domain and
|
|
||||||
* its sub-domains. For security reasons the user agent will not accept the cookie
|
|
||||||
* if the current domain is not a sub-domain of this domain or equal to it.
|
|
||||||
* - **expires** - `{string|Date}` - String of the form "Wdy, DD Mon YYYY HH:MM:SS GMT"
|
|
||||||
* or a Date object indicating the exact date/time this cookie will expire.
|
|
||||||
* - **secure** - `{boolean}` - If `true`, then the cookie will only be available through a
|
|
||||||
* secured connection.
|
|
||||||
* - **samesite** - `{string}` - prevents the browser from sending the cookie along with cross-site requests.
|
|
||||||
* Accepts the values `lax` and `strict`. See the [OWASP Wiki](https://www.owasp.org/index.php/SameSite)
|
|
||||||
* for more info. Note that as of May 2018, not all browsers support `SameSite`,
|
|
||||||
* so it cannot be used as a single measure against Cross-Site-Request-Forgery (CSRF) attacks.
|
|
||||||
*
|
|
||||||
* Note: By default, the address that appears in your `<base>` tag will be used as the path.
|
|
||||||
* This is important so that cookies will be visible for all routes when html5mode is enabled.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
* angular.module('cookiesProviderExample', ['ngCookies'])
|
|
||||||
* .config(['$cookiesProvider', function($cookiesProvider) {
|
|
||||||
* // Setting default options
|
|
||||||
* $cookiesProvider.defaults.domain = 'foo.com';
|
|
||||||
* $cookiesProvider.defaults.secure = true;
|
|
||||||
* }]);
|
|
||||||
* ```
|
|
||||||
**/
|
|
||||||
var defaults = this.defaults = {};
|
|
||||||
|
|
||||||
function calcOptions(options) {
|
|
||||||
return options ? angular.extend({}, defaults, options) : defaults;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc service
|
|
||||||
* @name $cookies
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Provides read/write access to browser's cookies.
|
|
||||||
*
|
|
||||||
* <div class="alert alert-info">
|
|
||||||
* Up until AngularJS 1.3, `$cookies` exposed properties that represented the
|
|
||||||
* current browser cookie values. In version 1.4, this behavior has changed, and
|
|
||||||
* `$cookies` now provides a standard api of getters, setters etc.
|
|
||||||
* </div>
|
|
||||||
*
|
|
||||||
* Requires the {@link ngCookies `ngCookies`} module to be installed.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
* angular.module('cookiesExample', ['ngCookies'])
|
|
||||||
* .controller('ExampleController', ['$cookies', function($cookies) {
|
|
||||||
* // Retrieving a cookie
|
|
||||||
* var favoriteCookie = $cookies.get('myFavorite');
|
|
||||||
* // Setting a cookie
|
|
||||||
* $cookies.put('myFavorite', 'oatmeal');
|
|
||||||
* }]);
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
this.$get = ['$$cookieReader', '$$cookieWriter', function($$cookieReader, $$cookieWriter) {
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name $cookies#get
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Returns the value of given cookie key
|
|
||||||
*
|
|
||||||
* @param {string} key Id to use for lookup.
|
|
||||||
* @returns {string} Raw cookie value.
|
|
||||||
*/
|
|
||||||
get: function(key) {
|
|
||||||
return $$cookieReader()[key];
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name $cookies#getObject
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Returns the deserialized value of given cookie key
|
|
||||||
*
|
|
||||||
* @param {string} key Id to use for lookup.
|
|
||||||
* @returns {Object} Deserialized cookie value.
|
|
||||||
*/
|
|
||||||
getObject: function(key) {
|
|
||||||
var value = this.get(key);
|
|
||||||
return value ? angular.fromJson(value) : value;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name $cookies#getAll
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Returns a key value object with all the cookies
|
|
||||||
*
|
|
||||||
* @returns {Object} All cookies
|
|
||||||
*/
|
|
||||||
getAll: function() {
|
|
||||||
return $$cookieReader();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name $cookies#put
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Sets a value for given cookie key
|
|
||||||
*
|
|
||||||
* @param {string} key Id for the `value`.
|
|
||||||
* @param {string} value Raw value to be stored.
|
|
||||||
* @param {Object=} options Options object.
|
|
||||||
* See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults}
|
|
||||||
*/
|
|
||||||
put: function(key, value, options) {
|
|
||||||
$$cookieWriter(key, value, calcOptions(options));
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name $cookies#putObject
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Serializes and sets a value for given cookie key
|
|
||||||
*
|
|
||||||
* @param {string} key Id for the `value`.
|
|
||||||
* @param {Object} value Value to be stored.
|
|
||||||
* @param {Object=} options Options object.
|
|
||||||
* See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults}
|
|
||||||
*/
|
|
||||||
putObject: function(key, value, options) {
|
|
||||||
this.put(key, angular.toJson(value), options);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name $cookies#remove
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Remove given cookie
|
|
||||||
*
|
|
||||||
* @param {string} key Id of the key-value pair to delete.
|
|
||||||
* @param {Object=} options Options object.
|
|
||||||
* See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults}
|
|
||||||
*/
|
|
||||||
remove: function(key, options) {
|
|
||||||
$$cookieWriter(key, undefined, calcOptions(options));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}];
|
|
||||||
}]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @name $$cookieWriter
|
|
||||||
* @requires $document
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* This is a private service for writing cookies
|
|
||||||
*
|
|
||||||
* @param {string} name Cookie name
|
|
||||||
* @param {string=} value Cookie value (if undefined, cookie will be deleted)
|
|
||||||
* @param {Object=} options Object with options that need to be stored for the cookie.
|
|
||||||
*/
|
|
||||||
function $$CookieWriter($document, $log, $browser) {
|
|
||||||
var cookiePath = $browser.baseHref();
|
|
||||||
var rawDocument = $document[0];
|
|
||||||
|
|
||||||
function buildCookieString(name, value, options) {
|
|
||||||
var path, expires;
|
|
||||||
options = options || {};
|
|
||||||
expires = options.expires;
|
|
||||||
path = angular.isDefined(options.path) ? options.path : cookiePath;
|
|
||||||
if (angular.isUndefined(value)) {
|
|
||||||
expires = 'Thu, 01 Jan 1970 00:00:00 GMT';
|
|
||||||
value = '';
|
|
||||||
}
|
|
||||||
if (angular.isString(expires)) {
|
|
||||||
expires = new Date(expires);
|
|
||||||
}
|
|
||||||
|
|
||||||
var str = encodeURIComponent(name) + '=' + encodeURIComponent(value);
|
|
||||||
str += path ? ';path=' + path : '';
|
|
||||||
str += options.domain ? ';domain=' + options.domain : '';
|
|
||||||
str += expires ? ';expires=' + expires.toUTCString() : '';
|
|
||||||
str += options.secure ? ';secure' : '';
|
|
||||||
str += options.samesite ? ';samesite=' + options.samesite : '';
|
|
||||||
|
|
||||||
// per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
|
|
||||||
// - 300 cookies
|
|
||||||
// - 20 cookies per unique domain
|
|
||||||
// - 4096 bytes per cookie
|
|
||||||
var cookieLength = str.length + 1;
|
|
||||||
if (cookieLength > 4096) {
|
|
||||||
$log.warn('Cookie \'' + name +
|
|
||||||
'\' possibly not set or overflowed because it was too large (' +
|
|
||||||
cookieLength + ' > 4096 bytes)!');
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
return function(name, value, options) {
|
|
||||||
rawDocument.cookie = buildCookieString(name, value, options);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
$$CookieWriter.$inject = ['$document', '$log', '$browser'];
|
|
||||||
|
|
||||||
angular.module('ngCookies').provider('$$cookieWriter', /** @this */ function $$CookieWriterProvider() {
|
|
||||||
this.$get = $$CookieWriter;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
})(window, window.angular);
|
|
|
@ -1,9 +0,0 @@
|
||||||
/*
|
|
||||||
AngularJS v1.8.0
|
|
||||||
(c) 2010-2020 Google, Inc. http://angularjs.org
|
|
||||||
License: MIT
|
|
||||||
*/
|
|
||||||
(function(n,e){'use strict';function m(d,k,l){var a=l.baseHref(),h=d[0];return function(f,b,c){var d,g;c=c||{};g=c.expires;d=e.isDefined(c.path)?c.path:a;e.isUndefined(b)&&(g="Thu, 01 Jan 1970 00:00:00 GMT",b="");e.isString(g)&&(g=new Date(g));b=encodeURIComponent(f)+"="+encodeURIComponent(b);b=b+(d?";path="+d:"")+(c.domain?";domain="+c.domain:"");b+=g?";expires="+g.toUTCString():"";b+=c.secure?";secure":"";b+=c.samesite?";samesite="+c.samesite:"";c=b.length+1;4096<c&&k.warn("Cookie '"+f+"' possibly not set or overflowed because it was too large ("+
|
|
||||||
c+" > 4096 bytes)!");h.cookie=b}}e.module("ngCookies",["ng"]).info({angularVersion:"1.8.0"}).provider("$cookies",[function(){var d=this.defaults={};this.$get=["$$cookieReader","$$cookieWriter",function(k,l){return{get:function(a){return k()[a]},getObject:function(a){return(a=this.get(a))?e.fromJson(a):a},getAll:function(){return k()},put:function(a,h,f){l(a,h,f?e.extend({},d,f):d)},putObject:function(a,d,f){this.put(a,e.toJson(d),f)},remove:function(a,h){l(a,void 0,h?e.extend({},d,h):d)}}}]}]);m.$inject=
|
|
||||||
["$document","$log","$browser"];e.module("ngCookies").provider("$$cookieWriter",function(){this.$get=m})})(window,window.angular);
|
|
||||||
//# sourceMappingURL=angular-cookies.min.js.map
|
|
|
@ -1,8 +0,0 @@
|
||||||
{
|
|
||||||
"version":3,
|
|
||||||
"file":"angular-cookies.min.js",
|
|
||||||
"lineCount":8,
|
|
||||||
"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkB,CAqM3BC,QAASA,EAAc,CAACC,CAAD,CAAYC,CAAZ,CAAkBC,CAAlB,CAA4B,CACjD,IAAIC,EAAaD,CAAAE,SAAA,EAAjB,CACIC,EAAcL,CAAA,CAAU,CAAV,CAoClB,OAAO,SAAQ,CAACM,CAAD,CAAOC,CAAP,CAAcC,CAAd,CAAuB,CAlCW,IAC3CC,CAD2C,CACrCC,CACVF,EAAA,CAiCoDA,CAjCpD,EAAqB,EACrBE,EAAA,CAAUF,CAAAE,QACVD,EAAA,CAAOX,CAAAa,UAAA,CAAkBH,CAAAC,KAAlB,CAAA,CAAkCD,CAAAC,KAAlC,CAAiDN,CACpDL,EAAAc,YAAA,CAAoBL,CAApB,CAAJ,GACEG,CACA,CADU,+BACV,CAAAH,CAAA,CAAQ,EAFV,CAIIT,EAAAe,SAAA,CAAiBH,CAAjB,CAAJ,GACEA,CADF,CACY,IAAII,IAAJ,CAASJ,CAAT,CADZ,CAIIK,EAAAA,CAAMC,kBAAA,CAsB6BV,CAtB7B,CAANS,CAAiC,GAAjCA,CAAuCC,kBAAA,CAAmBT,CAAnB,CAE3CQ,EAAA,CADAA,CACA,EADON,CAAA,CAAO,QAAP,CAAkBA,CAAlB,CAAyB,EAChC,GAAOD,CAAAS,OAAA,CAAiB,UAAjB,CAA8BT,CAAAS,OAA9B,CAA+C,EAAtD,CACAF,EAAA,EAAOL,CAAA,CAAU,WAAV,CAAwBA,CAAAQ,YAAA,EAAxB,CAAgD,EACvDH,EAAA,EAAOP,CAAAW,OAAA,CAAiB,SAAjB,CAA6B,EACpCJ,EAAA,EAAOP,CAAAY,SAAA,CAAmB,YAAnB,CAAkCZ,CAAAY,SAAlC,CAAqD,EAMxDC,EAAAA,CAAeN,CAAAO,OAAfD,CAA4B,CACb,KAAnB,CAAIA,CAAJ,EACEpB,CAAAsB,KAAA,CAAU,UAAV,CASqCjB,CATrC,CACE,6DADF;AAEEe,CAFF,CAEiB,iBAFjB,CASFhB,EAAAmB,OAAA,CAJOT,CAG6B,CAtCW,CAxLnDjB,CAAA2B,OAAA,CAAe,WAAf,CAA4B,CAAC,IAAD,CAA5B,CAAAC,KAAA,CACO,CAAEC,eAAgB,OAAlB,CADP,CAAAC,SAAA,CAQY,UARZ,CAQwB,CAAaC,QAAyB,EAAG,CAsC7D,IAAIC,EAAW,IAAAA,SAAXA,CAA2B,EAiC/B,KAAAC,KAAA,CAAY,CAAC,gBAAD,CAAmB,gBAAnB,CAAqC,QAAQ,CAACC,CAAD,CAAiBC,CAAjB,CAAiC,CACxF,MAAO,CAWLC,IAAKA,QAAQ,CAACC,CAAD,CAAM,CACjB,MAAOH,EAAA,EAAA,CAAiBG,CAAjB,CADU,CAXd,CAyBLC,UAAWA,QAAQ,CAACD,CAAD,CAAM,CAEvB,MAAO,CADH5B,CACG,CADK,IAAA2B,IAAA,CAASC,CAAT,CACL,EAAQrC,CAAAuC,SAAA,CAAiB9B,CAAjB,CAAR,CAAkCA,CAFlB,CAzBpB,CAuCL+B,OAAQA,QAAQ,EAAG,CACjB,MAAON,EAAA,EADU,CAvCd,CAuDLO,IAAKA,QAAQ,CAACJ,CAAD,CAAM5B,CAAN,CAAaC,CAAb,CAAsB,CACjCyB,CAAA,CAAeE,CAAf,CAAoB5B,CAApB,CAAuCC,CAvFpC,CAAUV,CAAA0C,OAAA,CAAe,EAAf,CAAmBV,CAAnB,CAuF0BtB,CAvF1B,CAAV,CAAkDsB,CAuFrD,CADiC,CAvD9B,CAuELW,UAAWA,QAAQ,CAACN,CAAD,CAAM5B,CAAN,CAAaC,CAAb,CAAsB,CACvC,IAAA+B,IAAA,CAASJ,CAAT,CAAcrC,CAAA4C,OAAA,CAAenC,CAAf,CAAd,CAAqCC,CAArC,CADuC,CAvEpC,CAsFLmC,OAAQA,QAAQ,CAACR,CAAD,CAAM3B,CAAN,CAAe,CAC7ByB,CAAA,CAAeE,CAAf,CAAoBS,IAAAA,EAApB,CAA2CpC,CAtHxC,CAAUV,CAAA0C,OAAA,CAAe,EAAf,CAAmBV,CAAnB,CAsH8BtB,CAtH9B,CAAV,CAAkDsB,CAsHrD,CAD6B,CAtF1B,CADiF,CAA9E,CAvEiD,CAAzC,CARxB,CAmOA/B,EAAA8C,QAAA;AAAyB,CAAC,WAAD,CAAc,MAAd,CAAsB,UAAtB,CAEzB/C,EAAA2B,OAAA,CAAe,WAAf,CAAAG,SAAA,CAAqC,gBAArC,CAAoEkB,QAA+B,EAAG,CACpG,IAAAf,KAAA,CAAYhC,CADwF,CAAtG,CAlP2B,CAA1B,CAAD,CAuPGF,MAvPH,CAuPWA,MAAAC,QAvPX;",
|
|
||||||
"sources":["angular-cookies.js"],
|
|
||||||
"names":["window","angular","$$CookieWriter","$document","$log","$browser","cookiePath","baseHref","rawDocument","name","value","options","path","expires","isDefined","isUndefined","isString","Date","str","encodeURIComponent","domain","toUTCString","secure","samesite","cookieLength","length","warn","cookie","module","info","angularVersion","provider","$CookiesProvider","defaults","$get","$$cookieReader","$$cookieWriter","get","key","getObject","fromJson","getAll","put","extend","putObject","toJson","remove","undefined","$inject","$$CookieWriterProvider"]
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"name": "angular-cookies",
|
|
||||||
"version": "1.8.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "./angular-cookies.js",
|
|
||||||
"ignore": [],
|
|
||||||
"dependencies": {
|
|
||||||
"angular": "1.8.0"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
require('./angular-cookies');
|
|
||||||
module.exports = 'ngCookies';
|
|
|
@ -1,63 +0,0 @@
|
||||||
{
|
|
||||||
"_from": "angular-cookies@1.8.0",
|
|
||||||
"_id": "angular-cookies@1.8.0",
|
|
||||||
"_inBundle": false,
|
|
||||||
"_integrity": "sha512-gWO3RKF0WMmXhseiN3Aw9aEmQ3mB53wSdAxpeKKHbiDwU7vmK+MBuebyOX9qbwZYubn5nM8LByZVmg7T6jOV1w==",
|
|
||||||
"_location": "/angular-cookies",
|
|
||||||
"_phantomChildren": {},
|
|
||||||
"_requested": {
|
|
||||||
"type": "version",
|
|
||||||
"registry": true,
|
|
||||||
"raw": "angular-cookies@1.8.0",
|
|
||||||
"name": "angular-cookies",
|
|
||||||
"escapedName": "angular-cookies",
|
|
||||||
"rawSpec": "1.8.0",
|
|
||||||
"saveSpec": null,
|
|
||||||
"fetchSpec": "1.8.0"
|
|
||||||
},
|
|
||||||
"_requiredBy": [
|
|
||||||
"/"
|
|
||||||
],
|
|
||||||
"_resolved": "https://registry.npmjs.org/angular-cookies/-/angular-cookies-1.8.0.tgz",
|
|
||||||
"_shasum": "c981c843652e716c1cf993451c2509f00a4b0169",
|
|
||||||
"_spec": "angular-cookies@1.8.0",
|
|
||||||
"_where": "/home/abstractj/github/keycloak/themes/src/main/resources/theme/keycloak/common/resources",
|
|
||||||
"author": {
|
|
||||||
"name": "Angular Core Team",
|
|
||||||
"email": "angular-core+npm@google.com"
|
|
||||||
},
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/angular/angular.js/issues"
|
|
||||||
},
|
|
||||||
"bundleDependencies": false,
|
|
||||||
"deprecated": false,
|
|
||||||
"description": "AngularJS module for cookies",
|
|
||||||
"homepage": "http://angularjs.org",
|
|
||||||
"jspm": {
|
|
||||||
"shim": {
|
|
||||||
"angular-cookies": {
|
|
||||||
"deps": [
|
|
||||||
"angular"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"angular",
|
|
||||||
"framework",
|
|
||||||
"browser",
|
|
||||||
"cookies",
|
|
||||||
"client-side"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "index.js",
|
|
||||||
"name": "angular-cookies",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/angular/angular.js.git"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"version": "1.8.0"
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2016 Angular
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
|
@ -1,65 +0,0 @@
|
||||||
# packaged angular-loader
|
|
||||||
|
|
||||||
This repo is for distribution on `npm` and `bower`. The source for this module is in the
|
|
||||||
[main AngularJS repo](https://github.com/angular/angular.js/blob/master/src/loader.js).
|
|
||||||
Please file issues and pull requests against that repo.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
You can install this package either with `npm` or with `bower`.
|
|
||||||
|
|
||||||
### npm
|
|
||||||
|
|
||||||
```shell
|
|
||||||
npm install angular-loader
|
|
||||||
```
|
|
||||||
|
|
||||||
Add a `<script>` to your `index.html`:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<script src="/node_modules/angular-loader/angular-loader.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that this package is not in CommonJS format, so doing `require('angular-loader')` will
|
|
||||||
return `undefined`.
|
|
||||||
|
|
||||||
### bower
|
|
||||||
|
|
||||||
```shell
|
|
||||||
bower install angular-loader
|
|
||||||
```
|
|
||||||
|
|
||||||
Add a `<script>` to your `index.html`:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<script src="/bower_components/angular-loader/angular-loader.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
Documentation is available on the
|
|
||||||
[AngularJS docs site](http://docs.angularjs.org/guide/bootstrap).
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
The MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
|
@ -1,638 +0,0 @@
|
||||||
/**
|
|
||||||
* @license AngularJS v1.8.0
|
|
||||||
* (c) 2010-2020 Google, Inc. http://angularjs.org
|
|
||||||
* License: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
(function() {'use strict';
|
|
||||||
// NOTE:
|
|
||||||
// These functions are copied here from `src/Angular.js`, because they are needed inside the
|
|
||||||
// `angular-loader.js` closure and need to be available before the main `angular.js` script has
|
|
||||||
// been loaded.
|
|
||||||
function isFunction(value) {return typeof value === 'function';}
|
|
||||||
function isDefined(value) {return typeof value !== 'undefined';}
|
|
||||||
function isNumber(value) {return typeof value === 'number';}
|
|
||||||
function isObject(value) {return value !== null && typeof value === 'object';}
|
|
||||||
function isScope(obj) {return obj && obj.$evalAsync && obj.$watch;}
|
|
||||||
function isUndefined(value) {return typeof value === 'undefined';}
|
|
||||||
function isWindow(obj) {return obj && obj.window === obj;}
|
|
||||||
function sliceArgs(args, startIndex) {return Array.prototype.slice.call(args, startIndex || 0);}
|
|
||||||
function toJsonReplacer(key, value) {
|
|
||||||
var val = value;
|
|
||||||
|
|
||||||
if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
|
|
||||||
val = undefined;
|
|
||||||
} else if (isWindow(value)) {
|
|
||||||
val = '$WINDOW';
|
|
||||||
} else if (value && window.document === value) {
|
|
||||||
val = '$DOCUMENT';
|
|
||||||
} else if (isScope(value)) {
|
|
||||||
val = '$SCOPE';
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* exported toDebugString */
|
|
||||||
|
|
||||||
function serializeObject(obj, maxDepth) {
|
|
||||||
var seen = [];
|
|
||||||
|
|
||||||
// There is no direct way to stringify object until reaching a specific depth
|
|
||||||
// and a very deep object can cause a performance issue, so we copy the object
|
|
||||||
// based on this specific depth and then stringify it.
|
|
||||||
if (isValidObjectMaxDepth(maxDepth)) {
|
|
||||||
// This file is also included in `angular-loader`, so `copy()` might not always be available in
|
|
||||||
// the closure. Therefore, it is lazily retrieved as `angular.copy()` when needed.
|
|
||||||
obj = angular.copy(obj, null, maxDepth);
|
|
||||||
}
|
|
||||||
return JSON.stringify(obj, function(key, val) {
|
|
||||||
val = toJsonReplacer(key, val);
|
|
||||||
if (isObject(val)) {
|
|
||||||
|
|
||||||
if (seen.indexOf(val) >= 0) return '...';
|
|
||||||
|
|
||||||
seen.push(val);
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function toDebugString(obj, maxDepth) {
|
|
||||||
if (typeof obj === 'function') {
|
|
||||||
return obj.toString().replace(/ \{[\s\S]*$/, '');
|
|
||||||
} else if (isUndefined(obj)) {
|
|
||||||
return 'undefined';
|
|
||||||
} else if (typeof obj !== 'string') {
|
|
||||||
return serializeObject(obj, maxDepth);
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* exported
|
|
||||||
minErrConfig,
|
|
||||||
errorHandlingConfig,
|
|
||||||
isValidObjectMaxDepth
|
|
||||||
*/
|
|
||||||
|
|
||||||
var minErrConfig = {
|
|
||||||
objectMaxDepth: 5,
|
|
||||||
urlErrorParamsEnabled: true
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name angular.errorHandlingConfig
|
|
||||||
* @module ng
|
|
||||||
* @kind function
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Configure several aspects of error handling in AngularJS if used as a setter or return the
|
|
||||||
* current configuration if used as a getter. The following options are supported:
|
|
||||||
*
|
|
||||||
* - **objectMaxDepth**: The maximum depth to which objects are traversed when stringified for error messages.
|
|
||||||
*
|
|
||||||
* Omitted or undefined options will leave the corresponding configuration values unchanged.
|
|
||||||
*
|
|
||||||
* @param {Object=} config - The configuration object. May only contain the options that need to be
|
|
||||||
* updated. Supported keys:
|
|
||||||
*
|
|
||||||
* * `objectMaxDepth` **{Number}** - The max depth for stringifying objects. Setting to a
|
|
||||||
* non-positive or non-numeric value, removes the max depth limit.
|
|
||||||
* Default: 5
|
|
||||||
*
|
|
||||||
* * `urlErrorParamsEnabled` **{Boolean}** - Specifies whether the generated error url will
|
|
||||||
* contain the parameters of the thrown error. Disabling the parameters can be useful if the
|
|
||||||
* generated error url is very long.
|
|
||||||
*
|
|
||||||
* Default: true. When used without argument, it returns the current value.
|
|
||||||
*/
|
|
||||||
function errorHandlingConfig(config) {
|
|
||||||
if (isObject(config)) {
|
|
||||||
if (isDefined(config.objectMaxDepth)) {
|
|
||||||
minErrConfig.objectMaxDepth = isValidObjectMaxDepth(config.objectMaxDepth) ? config.objectMaxDepth : NaN;
|
|
||||||
}
|
|
||||||
if (isDefined(config.urlErrorParamsEnabled) && isBoolean(config.urlErrorParamsEnabled)) {
|
|
||||||
minErrConfig.urlErrorParamsEnabled = config.urlErrorParamsEnabled;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return minErrConfig;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @param {Number} maxDepth
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
function isValidObjectMaxDepth(maxDepth) {
|
|
||||||
return isNumber(maxDepth) && maxDepth > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description
|
|
||||||
*
|
|
||||||
* This object provides a utility for producing rich Error messages within
|
|
||||||
* AngularJS. It can be called as follows:
|
|
||||||
*
|
|
||||||
* var exampleMinErr = minErr('example');
|
|
||||||
* throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
|
|
||||||
*
|
|
||||||
* The above creates an instance of minErr in the example namespace. The
|
|
||||||
* resulting error will have a namespaced error code of example.one. The
|
|
||||||
* resulting error will replace {0} with the value of foo, and {1} with the
|
|
||||||
* value of bar. The object is not restricted in the number of arguments it can
|
|
||||||
* take.
|
|
||||||
*
|
|
||||||
* If fewer arguments are specified than necessary for interpolation, the extra
|
|
||||||
* interpolation markers will be preserved in the final string.
|
|
||||||
*
|
|
||||||
* Since data will be parsed statically during a build step, some restrictions
|
|
||||||
* are applied with respect to how minErr instances are created and called.
|
|
||||||
* Instances should have names of the form namespaceMinErr for a minErr created
|
|
||||||
* using minErr('namespace'). Error codes, namespaces and template strings
|
|
||||||
* should all be static strings, not variables or general expressions.
|
|
||||||
*
|
|
||||||
* @param {string} module The namespace to use for the new minErr instance.
|
|
||||||
* @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
|
|
||||||
* error from returned function, for cases when a particular type of error is useful.
|
|
||||||
* @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
|
|
||||||
*/
|
|
||||||
|
|
||||||
function minErr(module, ErrorConstructor) {
|
|
||||||
ErrorConstructor = ErrorConstructor || Error;
|
|
||||||
|
|
||||||
var url = 'https://errors.angularjs.org/1.8.0/';
|
|
||||||
var regex = url.replace('.', '\\.') + '[\\s\\S]*';
|
|
||||||
var errRegExp = new RegExp(regex, 'g');
|
|
||||||
|
|
||||||
return function() {
|
|
||||||
var code = arguments[0],
|
|
||||||
template = arguments[1],
|
|
||||||
message = '[' + (module ? module + ':' : '') + code + '] ',
|
|
||||||
templateArgs = sliceArgs(arguments, 2).map(function(arg) {
|
|
||||||
return toDebugString(arg, minErrConfig.objectMaxDepth);
|
|
||||||
}),
|
|
||||||
paramPrefix, i;
|
|
||||||
|
|
||||||
// A minErr message has two parts: the message itself and the url that contains the
|
|
||||||
// encoded message.
|
|
||||||
// The message's parameters can contain other error messages which also include error urls.
|
|
||||||
// To prevent the messages from getting too long, we strip the error urls from the parameters.
|
|
||||||
|
|
||||||
message += template.replace(/\{\d+\}/g, function(match) {
|
|
||||||
var index = +match.slice(1, -1);
|
|
||||||
|
|
||||||
if (index < templateArgs.length) {
|
|
||||||
return templateArgs[index].replace(errRegExp, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
return match;
|
|
||||||
});
|
|
||||||
|
|
||||||
message += '\n' + url + (module ? module + '/' : '') + code;
|
|
||||||
|
|
||||||
if (minErrConfig.urlErrorParamsEnabled) {
|
|
||||||
for (i = 0, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
|
|
||||||
message += paramPrefix + 'p' + i + '=' + encodeURIComponent(templateArgs[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ErrorConstructor(message);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc type
|
|
||||||
* @name angular.Module
|
|
||||||
* @module ng
|
|
||||||
* @description
|
|
||||||
*
|
|
||||||
* Interface for configuring AngularJS {@link angular.module modules}.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function setupModuleLoader(window) {
|
|
||||||
|
|
||||||
var $injectorMinErr = minErr('$injector');
|
|
||||||
var ngMinErr = minErr('ng');
|
|
||||||
|
|
||||||
function ensure(obj, name, factory) {
|
|
||||||
return obj[name] || (obj[name] = factory());
|
|
||||||
}
|
|
||||||
|
|
||||||
var angular = ensure(window, 'angular', Object);
|
|
||||||
|
|
||||||
// We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
|
|
||||||
angular.$$minErr = angular.$$minErr || minErr;
|
|
||||||
|
|
||||||
return ensure(angular, 'module', function() {
|
|
||||||
/** @type {Object.<string, angular.Module>} */
|
|
||||||
var modules = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name angular.module
|
|
||||||
* @module ng
|
|
||||||
* @description
|
|
||||||
*
|
|
||||||
* The `angular.module` is a global place for creating, registering and retrieving AngularJS
|
|
||||||
* modules.
|
|
||||||
* All modules (AngularJS core or 3rd party) that should be available to an application must be
|
|
||||||
* registered using this mechanism.
|
|
||||||
*
|
|
||||||
* Passing one argument retrieves an existing {@link angular.Module},
|
|
||||||
* whereas passing more than one argument creates a new {@link angular.Module}
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* # Module
|
|
||||||
*
|
|
||||||
* A module is a collection of services, directives, controllers, filters, and configuration information.
|
|
||||||
* `angular.module` is used to configure the {@link auto.$injector $injector}.
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
* // Create a new module
|
|
||||||
* var myModule = angular.module('myModule', []);
|
|
||||||
*
|
|
||||||
* // register a new service
|
|
||||||
* myModule.value('appName', 'MyCoolApp');
|
|
||||||
*
|
|
||||||
* // configure existing services inside initialization blocks.
|
|
||||||
* myModule.config(['$locationProvider', function($locationProvider) {
|
|
||||||
* // Configure existing providers
|
|
||||||
* $locationProvider.hashPrefix('!');
|
|
||||||
* }]);
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Then you can create an injector and load your modules like this:
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
* var injector = angular.injector(['ng', 'myModule'])
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* However it's more likely that you'll just use
|
|
||||||
* {@link ng.directive:ngApp ngApp} or
|
|
||||||
* {@link angular.bootstrap} to simplify this process for you.
|
|
||||||
*
|
|
||||||
* @param {!string} name The name of the module to create or retrieve.
|
|
||||||
* @param {!Array.<string>=} requires If specified then new module is being created. If
|
|
||||||
* unspecified then the module is being retrieved for further configuration.
|
|
||||||
* @param {Function=} configFn Optional configuration function for the module. Same as
|
|
||||||
* {@link angular.Module#config Module#config()}.
|
|
||||||
* @returns {angular.Module} new module with the {@link angular.Module} api.
|
|
||||||
*/
|
|
||||||
return function module(name, requires, configFn) {
|
|
||||||
|
|
||||||
var info = {};
|
|
||||||
|
|
||||||
var assertNotHasOwnProperty = function(name, context) {
|
|
||||||
if (name === 'hasOwnProperty') {
|
|
||||||
throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
assertNotHasOwnProperty(name, 'module');
|
|
||||||
if (requires && modules.hasOwnProperty(name)) {
|
|
||||||
modules[name] = null;
|
|
||||||
}
|
|
||||||
return ensure(modules, name, function() {
|
|
||||||
if (!requires) {
|
|
||||||
throw $injectorMinErr('nomod', 'Module \'{0}\' is not available! You either misspelled ' +
|
|
||||||
'the module name or forgot to load it. If registering a module ensure that you ' +
|
|
||||||
'specify the dependencies as the second argument.', name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @type {!Array.<Array.<*>>} */
|
|
||||||
var invokeQueue = [];
|
|
||||||
|
|
||||||
/** @type {!Array.<Function>} */
|
|
||||||
var configBlocks = [];
|
|
||||||
|
|
||||||
/** @type {!Array.<Function>} */
|
|
||||||
var runBlocks = [];
|
|
||||||
|
|
||||||
var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
|
|
||||||
|
|
||||||
/** @type {angular.Module} */
|
|
||||||
var moduleInstance = {
|
|
||||||
// Private state
|
|
||||||
_invokeQueue: invokeQueue,
|
|
||||||
_configBlocks: configBlocks,
|
|
||||||
_runBlocks: runBlocks,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#info
|
|
||||||
* @module ng
|
|
||||||
*
|
|
||||||
* @param {Object=} info Information about the module
|
|
||||||
* @returns {Object|Module} The current info object for this module if called as a getter,
|
|
||||||
* or `this` if called as a setter.
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Read and write custom information about this module.
|
|
||||||
* For example you could put the version of the module in here.
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
* angular.module('myModule', []).info({ version: '1.0.0' });
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* The version could then be read back out by accessing the module elsewhere:
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* var version = angular.module('myModule').info().version;
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* You can also retrieve this information during runtime via the
|
|
||||||
* {@link $injector#modules `$injector.modules`} property:
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
* var version = $injector.modules['myModule'].info().version;
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
info: function(value) {
|
|
||||||
if (isDefined(value)) {
|
|
||||||
if (!isObject(value)) throw ngMinErr('aobj', 'Argument \'{0}\' must be an object', 'value');
|
|
||||||
info = value;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
return info;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc property
|
|
||||||
* @name angular.Module#requires
|
|
||||||
* @module ng
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Holds the list of modules which the injector will load before the current module is
|
|
||||||
* loaded.
|
|
||||||
*/
|
|
||||||
requires: requires,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc property
|
|
||||||
* @name angular.Module#name
|
|
||||||
* @module ng
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Name of the module.
|
|
||||||
*/
|
|
||||||
name: name,
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#provider
|
|
||||||
* @module ng
|
|
||||||
* @param {string} name service name
|
|
||||||
* @param {Function} providerType Construction function for creating new instance of the
|
|
||||||
* service.
|
|
||||||
* @description
|
|
||||||
* See {@link auto.$provide#provider $provide.provider()}.
|
|
||||||
*/
|
|
||||||
provider: invokeLaterAndSetModuleName('$provide', 'provider'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#factory
|
|
||||||
* @module ng
|
|
||||||
* @param {string} name service name
|
|
||||||
* @param {Function} providerFunction Function for creating new instance of the service.
|
|
||||||
* @description
|
|
||||||
* See {@link auto.$provide#factory $provide.factory()}.
|
|
||||||
*/
|
|
||||||
factory: invokeLaterAndSetModuleName('$provide', 'factory'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#service
|
|
||||||
* @module ng
|
|
||||||
* @param {string} name service name
|
|
||||||
* @param {Function} constructor A constructor function that will be instantiated.
|
|
||||||
* @description
|
|
||||||
* See {@link auto.$provide#service $provide.service()}.
|
|
||||||
*/
|
|
||||||
service: invokeLaterAndSetModuleName('$provide', 'service'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#value
|
|
||||||
* @module ng
|
|
||||||
* @param {string} name service name
|
|
||||||
* @param {*} object Service instance object.
|
|
||||||
* @description
|
|
||||||
* See {@link auto.$provide#value $provide.value()}.
|
|
||||||
*/
|
|
||||||
value: invokeLater('$provide', 'value'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#constant
|
|
||||||
* @module ng
|
|
||||||
* @param {string} name constant name
|
|
||||||
* @param {*} object Constant value.
|
|
||||||
* @description
|
|
||||||
* Because the constants are fixed, they get applied before other provide methods.
|
|
||||||
* See {@link auto.$provide#constant $provide.constant()}.
|
|
||||||
*/
|
|
||||||
constant: invokeLater('$provide', 'constant', 'unshift'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#decorator
|
|
||||||
* @module ng
|
|
||||||
* @param {string} name The name of the service to decorate.
|
|
||||||
* @param {Function} decorFn This function will be invoked when the service needs to be
|
|
||||||
* instantiated and should return the decorated service instance.
|
|
||||||
* @description
|
|
||||||
* See {@link auto.$provide#decorator $provide.decorator()}.
|
|
||||||
*/
|
|
||||||
decorator: invokeLaterAndSetModuleName('$provide', 'decorator', configBlocks),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#animation
|
|
||||||
* @module ng
|
|
||||||
* @param {string} name animation name
|
|
||||||
* @param {Function} animationFactory Factory function for creating new instance of an
|
|
||||||
* animation.
|
|
||||||
* @description
|
|
||||||
*
|
|
||||||
* **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Defines an animation hook that can be later used with
|
|
||||||
* {@link $animate $animate} service and directives that use this service.
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
* module.animation('.animation-name', function($inject1, $inject2) {
|
|
||||||
* return {
|
|
||||||
* eventName : function(element, done) {
|
|
||||||
* //code to run the animation
|
|
||||||
* //once complete, then run done()
|
|
||||||
* return function cancellationFunction(element) {
|
|
||||||
* //code to cancel the animation
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* See {@link ng.$animateProvider#register $animateProvider.register()} and
|
|
||||||
* {@link ngAnimate ngAnimate module} for more information.
|
|
||||||
*/
|
|
||||||
animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#filter
|
|
||||||
* @module ng
|
|
||||||
* @param {string} name Filter name - this must be a valid AngularJS expression identifier
|
|
||||||
* @param {Function} filterFactory Factory function for creating new instance of filter.
|
|
||||||
* @description
|
|
||||||
* See {@link ng.$filterProvider#register $filterProvider.register()}.
|
|
||||||
*
|
|
||||||
* <div class="alert alert-warning">
|
|
||||||
* **Note:** Filter names must be valid AngularJS {@link expression} identifiers, such as `uppercase` or `orderBy`.
|
|
||||||
* Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
|
|
||||||
* your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
|
|
||||||
* (`myapp_subsection_filterx`).
|
|
||||||
* </div>
|
|
||||||
*/
|
|
||||||
filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#controller
|
|
||||||
* @module ng
|
|
||||||
* @param {string|Object} name Controller name, or an object map of controllers where the
|
|
||||||
* keys are the names and the values are the constructors.
|
|
||||||
* @param {Function} constructor Controller constructor function.
|
|
||||||
* @description
|
|
||||||
* See {@link ng.$controllerProvider#register $controllerProvider.register()}.
|
|
||||||
*/
|
|
||||||
controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#directive
|
|
||||||
* @module ng
|
|
||||||
* @param {string|Object} name Directive name, or an object map of directives where the
|
|
||||||
* keys are the names and the values are the factories.
|
|
||||||
* @param {Function} directiveFactory Factory function for creating new instance of
|
|
||||||
* directives.
|
|
||||||
* @description
|
|
||||||
* See {@link ng.$compileProvider#directive $compileProvider.directive()}.
|
|
||||||
*/
|
|
||||||
directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#component
|
|
||||||
* @module ng
|
|
||||||
* @param {string|Object} name Name of the component in camelCase (i.e. `myComp` which will match `<my-comp>`),
|
|
||||||
* or an object map of components where the keys are the names and the values are the component definition objects.
|
|
||||||
* @param {Object} options Component definition object (a simplified
|
|
||||||
* {@link ng.$compile#directive-definition-object directive definition object})
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* See {@link ng.$compileProvider#component $compileProvider.component()}.
|
|
||||||
*/
|
|
||||||
component: invokeLaterAndSetModuleName('$compileProvider', 'component'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#config
|
|
||||||
* @module ng
|
|
||||||
* @param {Function} configFn Execute this function on module load. Useful for service
|
|
||||||
* configuration.
|
|
||||||
* @description
|
|
||||||
* Use this method to configure services by injecting their
|
|
||||||
* {@link angular.Module#provider `providers`}, e.g. for adding routes to the
|
|
||||||
* {@link ngRoute.$routeProvider $routeProvider}.
|
|
||||||
*
|
|
||||||
* Note that you can only inject {@link angular.Module#provider `providers`} and
|
|
||||||
* {@link angular.Module#constant `constants`} into this function.
|
|
||||||
*
|
|
||||||
* For more about how to configure services, see
|
|
||||||
* {@link providers#provider-recipe Provider Recipe}.
|
|
||||||
*/
|
|
||||||
config: config,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#run
|
|
||||||
* @module ng
|
|
||||||
* @param {Function} initializationFn Execute this function after injector creation.
|
|
||||||
* Useful for application initialization.
|
|
||||||
* @description
|
|
||||||
* Use this method to register work which should be performed when the injector is done
|
|
||||||
* loading all modules.
|
|
||||||
*/
|
|
||||||
run: function(block) {
|
|
||||||
runBlocks.push(block);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (configFn) {
|
|
||||||
config(configFn);
|
|
||||||
}
|
|
||||||
|
|
||||||
return moduleInstance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} provider
|
|
||||||
* @param {string} method
|
|
||||||
* @param {String=} insertMethod
|
|
||||||
* @returns {angular.Module}
|
|
||||||
*/
|
|
||||||
function invokeLater(provider, method, insertMethod, queue) {
|
|
||||||
if (!queue) queue = invokeQueue;
|
|
||||||
return function() {
|
|
||||||
queue[insertMethod || 'push']([provider, method, arguments]);
|
|
||||||
return moduleInstance;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} provider
|
|
||||||
* @param {string} method
|
|
||||||
* @returns {angular.Module}
|
|
||||||
*/
|
|
||||||
function invokeLaterAndSetModuleName(provider, method, queue) {
|
|
||||||
if (!queue) queue = invokeQueue;
|
|
||||||
return function(recipeName, factoryFunction) {
|
|
||||||
if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
|
|
||||||
queue.push([provider, method, arguments]);
|
|
||||||
return moduleInstance;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
setupModuleLoader(window);
|
|
||||||
})(window);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closure compiler type information
|
|
||||||
*
|
|
||||||
* @typedef { {
|
|
||||||
* requires: !Array.<string>,
|
|
||||||
* invokeQueue: !Array.<Array.<*>>,
|
|
||||||
*
|
|
||||||
* service: function(string, Function):angular.Module,
|
|
||||||
* factory: function(string, Function):angular.Module,
|
|
||||||
* value: function(string, *):angular.Module,
|
|
||||||
*
|
|
||||||
* filter: function(string, Function):angular.Module,
|
|
||||||
*
|
|
||||||
* init: function(Function):angular.Module
|
|
||||||
* } }
|
|
||||||
*/
|
|
||||||
angular.Module;
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
/*
|
|
||||||
AngularJS v1.8.0
|
|
||||||
(c) 2010-2020 Google, Inc. http://angularjs.org
|
|
||||||
License: MIT
|
|
||||||
*/
|
|
||||||
(function(){'use strict';function g(a,f){f=f||Error;return function(){var d=arguments[0],e;e="["+(a?a+":":"")+d+"] http://errors.angularjs.org/1.8.0/"+(a?a+"/":"")+d;for(d=1;d<arguments.length;d++){e=e+(1==d?"?":"&")+"p"+(d-1)+"=";var q=encodeURIComponent,b;b=arguments[d];b="function"==typeof b?b.toString().replace(/ \{[\s\S]*$/,""):"undefined"==typeof b?"undefined":"string"!=typeof b?JSON.stringify(b):b;e+=q(b)}return new f(e)}}(function(a){function f(a,b,d){return a[b]||(a[b]=d())}var d=g("$injector"),
|
|
||||||
e=g("ng");a=f(a,"angular",Object);a.$$minErr=a.$$minErr||g;return f(a,"module",function(){var a={};return function(b,g,l){var m={};if("hasOwnProperty"===b)throw e("badname","module");g&&a.hasOwnProperty(b)&&(a[b]=null);return f(a,b,function(){function a(b,d,e,c){c||(c=f);return function(){c[e||"push"]([b,d,arguments]);return h}}function c(a,d,c){c||(c=f);return function(f,e){e&&"function"===typeof e&&(e.$$moduleName=b);c.push([a,d,arguments]);return h}}if(!g)throw d("nomod",b);var f=[],k=[],n=[],
|
|
||||||
p=a("$injector","invoke","push",k),h={_invokeQueue:f,_configBlocks:k,_runBlocks:n,info:function(a){if("undefined"!==typeof a){if(null===a||"object"!==typeof a)throw e("aobj","value");m=a;return this}return m},requires:g,name:b,provider:c("$provide","provider"),factory:c("$provide","factory"),service:c("$provide","service"),value:a("$provide","value"),constant:a("$provide","constant","unshift"),decorator:c("$provide","decorator",k),animation:c("$animateProvider","register"),filter:c("$filterProvider",
|
|
||||||
"register"),controller:c("$controllerProvider","register"),directive:c("$compileProvider","directive"),component:c("$compileProvider","component"),config:p,run:function(a){n.push(a);return this}};l&&p(l);return h})}})})(window)})(window);
|
|
||||||
//# sourceMappingURL=angular-loader.min.js.map
|
|
|
@ -1,8 +0,0 @@
|
||||||
{
|
|
||||||
"version":3,
|
|
||||||
"file":"angular-loader.min.js",
|
|
||||||
"lineCount":9,
|
|
||||||
"mappings":"A;;;;;aAMC,SAAQ,EAAG,CA4JZA,QAAAA,EAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,EAAAA,KAAAA,OAAAA,SAAAA,EAAAA,CAAAA,IAAAA,EAAAA,SAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,EAAAA,CAAAA,GAAAA,EAAAA,CAAAA,CAAAA,CAAAA,CAAAA,GAAAA,CAAAA,EAAAA,EAAAA,CAAAA,CAAAA,sCAAAA,EAAAA,CAAAA,CAAAA,CAAAA,CAAAA,GAAAA,CAAAA,EAAAA,EAAAA,CAAAA,KAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,SAAAA,OAAAA,CAAAA,CAAAA,EAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,EAAAA,CAAAA,EAAAA,CAAAA,CAAAA,GAAAA,CAAAA,GAAAA,EAAAA,GAAAA,EAAAA,CAAAA,CAAAA,CAAAA,EAAAA,GAAAA,KAAAA,EAAAA,kBAAAA,CAAAA,CAAAA,EAAAA,CAAAA,SAAAA,CAAAA,CAAAA,CAAAA,EAAAA,CAAAA,UAAAA,EAAAA,MAAAA,EAAAA,CAAAA,CAAAA,SAAAA,EAAAA,QAAAA,CAAAA,aAAAA,CAAAA,EAAAA,CAAAA,CAAAA,WAAAA,EAAAA,MAAAA,EAAAA,CAAAA,WAAAA,CAAAA,QAAAA,EAAAA,MAAAA,EAAAA,CAAAA,IAAAA,UAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,EAAAA,EAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,MAAAA,KAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAoDAC,SAA0B,CAACC,CAAD,CAAS,CAKjCC,QAASA,EAAM,CAACC,CAAD,CAAMC,CAAN,CAAYC,CAAZ,CAAqB,CAClC,MAAOF,EAAA,CAAIC,CAAJ,CAAP,GAAqBD,CAAA,CAAIC,CAAJ,CAArB,CAAiCC,CAAA,EAAjC,CADkC,CAHpC,IAAIC,EAAkBP,CAAA,CAAO,WAAP,CAAtB;AACIQ,EAAWR,CAAA,CAAO,IAAP,CAMXS,EAAAA,CAAUN,CAAA,CAAOD,CAAP,CAAe,SAAf,CAA0BQ,MAA1B,CAGdD,EAAAE,SAAA,CAAmBF,CAAAE,SAAnB,EAAuCX,CAEvC,OAAOG,EAAA,CAAOM,CAAP,CAAgB,QAAhB,CAA0B,QAAQ,EAAG,CAE1C,IAAIG,EAAU,EAqDd,OAAOC,SAAe,CAACR,CAAD,CAAOS,CAAP,CAAiBC,CAAjB,CAA2B,CAE/C,IAAIC,EAAO,EAGT,IAAa,gBAAb,GAKsBX,CALtB,CACE,KAAMG,EAAA,CAAS,SAAT,CAIoBS,QAJpB,CAAN,CAKAH,CAAJ,EAAgBF,CAAAM,eAAA,CAAuBb,CAAvB,CAAhB,GACEO,CAAA,CAAQP,CAAR,CADF,CACkB,IADlB,CAGA,OAAOF,EAAA,CAAOS,CAAP,CAAgBP,CAAhB,CAAsB,QAAQ,EAAG,CAqStCc,QAASA,EAAW,CAACC,CAAD,CAAWC,CAAX,CAAmBC,CAAnB,CAAiCC,CAAjC,CAAwC,CACrDA,CAAL,GAAYA,CAAZ,CAAoBC,CAApB,CACA,OAAO,SAAQ,EAAG,CAChBD,CAAA,CAAMD,CAAN,EAAsB,MAAtB,CAAA,CAA8B,CAACF,CAAD,CAAWC,CAAX,CAAmBI,SAAnB,CAA9B,CACA,OAAOC,EAFS,CAFwC,CAa5DC,QAASA,EAA2B,CAACP,CAAD,CAAWC,CAAX,CAAmBE,CAAnB,CAA0B,CACvDA,CAAL,GAAYA,CAAZ,CAAoBC,CAApB,CACA,OAAO,SAAQ,CAACI,CAAD,CAAaC,CAAb,CAA8B,CACvCA,CAAJ,EAnlB4C,UAmlB5C,GAnlB2B,MAmlBOA,EAAlC,GAAoDA,CAAAC,aAApD,CAAmFzB,CAAnF,CACAkB,EAAAQ,KAAA,CAAW,CAACX,CAAD,CAAWC,CAAX,CAAmBI,SAAnB,CAAX,CACA,OAAOC,EAHoC,CAFe,CAjT9D,GAAKZ,CAAAA,CAAL,CACE,KAAMP,EAAA,CAAgB,OAAhB,CAEiDF,CAFjD,CAAN,CAMF,IAAImB,EAAc,EAAlB,CAGIQ,EAAe,EAHnB,CAMIC,EAAY,EANhB;AAQIC,EAASf,CAAA,CAAY,WAAZ,CAAyB,QAAzB,CAAmC,MAAnC,CAA2Ca,CAA3C,CARb,CAWIN,EAAiB,CAEnBS,aAAcX,CAFK,CAGnBY,cAAeJ,CAHI,CAInBK,WAAYJ,CAJO,CAoCnBjB,KAAMA,QAAQ,CAACsB,CAAD,CAAQ,CACpB,GArV2C,WAqV3C,GArV0B,MAqVZA,EAAd,CAAsB,CACpB,GApViC,IAoVjC,GAAcA,CAAd,EApV0D,QAoV1D,GApVyC,MAoV3BA,EAAd,CAAsB,KAAM9B,EAAA,CAAS,MAAT,CAAuD,OAAvD,CAAN,CACtBQ,CAAA,CAAOsB,CACP,OAAO,KAHa,CAKtB,MAAOtB,EANa,CApCH,CAsDnBF,SAAUA,CAtDS,CAgEnBT,KAAMA,CAhEa,CA6EnBe,SAAUO,CAAA,CAA4B,UAA5B,CAAwC,UAAxC,CA7ES,CAwFnBrB,QAASqB,CAAA,CAA4B,UAA5B,CAAwC,SAAxC,CAxFU,CAmGnBY,QAASZ,CAAA,CAA4B,UAA5B,CAAwC,SAAxC,CAnGU,CA8GnBW,MAAOnB,CAAA,CAAY,UAAZ,CAAwB,OAAxB,CA9GY,CA0HnBqB,SAAUrB,CAAA,CAAY,UAAZ,CAAwB,UAAxB,CAAoC,SAApC,CA1HS,CAsInBsB,UAAWd,CAAA,CAA4B,UAA5B,CAAwC,WAAxC,CAAqDK,CAArD,CAtIQ,CAwKnBU,UAAWf,CAAA,CAA4B,kBAA5B,CAAgD,UAAhD,CAxKQ,CA0LnBgB,OAAQhB,CAAA,CAA4B,iBAA5B;AAA+C,UAA/C,CA1LW,CAsMnBiB,WAAYjB,CAAA,CAA4B,qBAA5B,CAAmD,UAAnD,CAtMO,CAmNnBkB,UAAWlB,CAAA,CAA4B,kBAA5B,CAAgD,WAAhD,CAnNQ,CAiOnBmB,UAAWnB,CAAA,CAA4B,kBAA5B,CAAgD,WAAhD,CAjOQ,CAoPnBO,OAAQA,CApPW,CAgQnBa,IAAKA,QAAQ,CAACC,CAAD,CAAQ,CACnBf,CAAAF,KAAA,CAAeiB,CAAf,CACA,OAAO,KAFY,CAhQF,CAsQjBjC,EAAJ,EACEmB,CAAA,CAAOnB,CAAP,CAGF,OAAOW,EA7R+B,CAAjC,CAdwC,CAvDP,CAArC,CAd0B,CAAnCzB,CAmZA,CAAkBC,MAAlB,CAnmBY,CAAX,CAAD,CAomBGA,MApmBH;",
|
|
||||||
"sources":["angular-loader.js"],
|
|
||||||
"names":["minErr","setupModuleLoader","window","ensure","obj","name","factory","$injectorMinErr","ngMinErr","angular","Object","$$minErr","modules","module","requires","configFn","info","context","hasOwnProperty","invokeLater","provider","method","insertMethod","queue","invokeQueue","arguments","moduleInstance","invokeLaterAndSetModuleName","recipeName","factoryFunction","$$moduleName","push","configBlocks","runBlocks","config","_invokeQueue","_configBlocks","_runBlocks","value","service","constant","decorator","animation","filter","controller","directive","component","run","block"]
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"name": "angular-loader",
|
|
||||||
"version": "1.8.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "./angular-loader.js",
|
|
||||||
"ignore": [],
|
|
||||||
"dependencies": {
|
|
||||||
"angular": "1.8.0"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
{
|
|
||||||
"_from": "angular-loader@1.8.0",
|
|
||||||
"_id": "angular-loader@1.8.0",
|
|
||||||
"_inBundle": false,
|
|
||||||
"_integrity": "sha512-NCvLLFWCkxLR3/zBaVGM+7q9IJzobx2PVXMnPoKjtAITpM6AhnH5SYFkFzcK1oQ6P6c2v0oLef6oij7mSEj0Mw==",
|
|
||||||
"_location": "/angular-loader",
|
|
||||||
"_phantomChildren": {},
|
|
||||||
"_requested": {
|
|
||||||
"type": "version",
|
|
||||||
"registry": true,
|
|
||||||
"raw": "angular-loader@1.8.0",
|
|
||||||
"name": "angular-loader",
|
|
||||||
"escapedName": "angular-loader",
|
|
||||||
"rawSpec": "1.8.0",
|
|
||||||
"saveSpec": null,
|
|
||||||
"fetchSpec": "1.8.0"
|
|
||||||
},
|
|
||||||
"_requiredBy": [
|
|
||||||
"/"
|
|
||||||
],
|
|
||||||
"_resolved": "https://registry.npmjs.org/angular-loader/-/angular-loader-1.8.0.tgz",
|
|
||||||
"_shasum": "63bbe97b44ca141fbc4fbde899904a81ed648c65",
|
|
||||||
"_spec": "angular-loader@1.8.0",
|
|
||||||
"_where": "/home/abstractj/github/keycloak/themes/src/main/resources/theme/keycloak/common/resources",
|
|
||||||
"author": {
|
|
||||||
"name": "Angular Core Team",
|
|
||||||
"email": "angular-core+npm@google.com"
|
|
||||||
},
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/angular/angular.js/issues"
|
|
||||||
},
|
|
||||||
"bundleDependencies": false,
|
|
||||||
"deprecated": false,
|
|
||||||
"description": "AngularJS module for asynchronously loading modules",
|
|
||||||
"homepage": "http://angularjs.org",
|
|
||||||
"jspm": {
|
|
||||||
"shim": {
|
|
||||||
"angular-loader": {
|
|
||||||
"deps": [
|
|
||||||
"angular"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"angular",
|
|
||||||
"framework",
|
|
||||||
"browser",
|
|
||||||
"loader",
|
|
||||||
"client-side"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "angular-loader.js",
|
|
||||||
"name": "angular-loader",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/angular/angular.js.git"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"version": "1.8.0"
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2016 Angular
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
|
@ -1,68 +0,0 @@
|
||||||
# packaged angular-resource
|
|
||||||
|
|
||||||
This repo is for distribution on `npm` and `bower`. The source for this module is in the
|
|
||||||
[main AngularJS repo](https://github.com/angular/angular.js/tree/master/src/ngResource).
|
|
||||||
Please file issues and pull requests against that repo.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
You can install this package either with `npm` or with `bower`.
|
|
||||||
|
|
||||||
### npm
|
|
||||||
|
|
||||||
```shell
|
|
||||||
npm install angular-resource
|
|
||||||
```
|
|
||||||
|
|
||||||
Then add `ngResource` as a dependency for your app:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
angular.module('myApp', [require('angular-resource')]);
|
|
||||||
```
|
|
||||||
|
|
||||||
### bower
|
|
||||||
|
|
||||||
```shell
|
|
||||||
bower install angular-resource
|
|
||||||
```
|
|
||||||
|
|
||||||
Add a `<script>` to your `index.html`:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<script src="/bower_components/angular-resource/angular-resource.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
Then add `ngResource` as a dependency for your app:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
angular.module('myApp', ['ngResource']);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
Documentation is available on the
|
|
||||||
[AngularJS docs site](http://docs.angularjs.org/api/ngResource).
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
The MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
|
@ -1,911 +0,0 @@
|
||||||
/**
|
|
||||||
* @license AngularJS v1.8.0
|
|
||||||
* (c) 2010-2020 Google, Inc. http://angularjs.org
|
|
||||||
* License: MIT
|
|
||||||
*/
|
|
||||||
(function(window, angular) {'use strict';
|
|
||||||
|
|
||||||
var $resourceMinErr = angular.$$minErr('$resource');
|
|
||||||
|
|
||||||
// Helper functions and regex to lookup a dotted path on an object
|
|
||||||
// stopping at undefined/null. The path must be composed of ASCII
|
|
||||||
// identifiers (just like $parse)
|
|
||||||
var MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;
|
|
||||||
|
|
||||||
function isValidDottedPath(path) {
|
|
||||||
return (path != null && path !== '' && path !== 'hasOwnProperty' &&
|
|
||||||
MEMBER_NAME_REGEX.test('.' + path));
|
|
||||||
}
|
|
||||||
|
|
||||||
function lookupDottedPath(obj, path) {
|
|
||||||
if (!isValidDottedPath(path)) {
|
|
||||||
throw $resourceMinErr('badmember', 'Dotted member path "@{0}" is invalid.', path);
|
|
||||||
}
|
|
||||||
var keys = path.split('.');
|
|
||||||
for (var i = 0, ii = keys.length; i < ii && angular.isDefined(obj); i++) {
|
|
||||||
var key = keys[i];
|
|
||||||
obj = (obj !== null) ? obj[key] : undefined;
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a shallow copy of an object and clear other fields from the destination
|
|
||||||
*/
|
|
||||||
function shallowClearAndCopy(src, dst) {
|
|
||||||
dst = dst || {};
|
|
||||||
|
|
||||||
angular.forEach(dst, function(value, key) {
|
|
||||||
delete dst[key];
|
|
||||||
});
|
|
||||||
|
|
||||||
for (var key in src) {
|
|
||||||
if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
|
|
||||||
dst[key] = src[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc module
|
|
||||||
* @name ngResource
|
|
||||||
* @description
|
|
||||||
*
|
|
||||||
* The `ngResource` module provides interaction support with RESTful services
|
|
||||||
* via the $resource service.
|
|
||||||
*
|
|
||||||
* See {@link ngResource.$resourceProvider} and {@link ngResource.$resource} for usage.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc provider
|
|
||||||
* @name $resourceProvider
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
*
|
|
||||||
* Use `$resourceProvider` to change the default behavior of the {@link ngResource.$resource}
|
|
||||||
* service.
|
|
||||||
*
|
|
||||||
* ## Dependencies
|
|
||||||
* Requires the {@link ngResource } module to be installed.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc service
|
|
||||||
* @name $resource
|
|
||||||
* @requires $http
|
|
||||||
* @requires ng.$log
|
|
||||||
* @requires $q
|
|
||||||
* @requires ng.$timeout
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* A factory which creates a resource object that lets you interact with
|
|
||||||
* [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources.
|
|
||||||
*
|
|
||||||
* The returned resource object has action methods which provide high-level behaviors without
|
|
||||||
* the need to interact with the low level {@link ng.$http $http} service.
|
|
||||||
*
|
|
||||||
* Requires the {@link ngResource `ngResource`} module to be installed.
|
|
||||||
*
|
|
||||||
* By default, trailing slashes will be stripped from the calculated URLs,
|
|
||||||
* which can pose problems with server backends that do not expect that
|
|
||||||
* behavior. This can be disabled by configuring the `$resourceProvider` like
|
|
||||||
* this:
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
app.config(['$resourceProvider', function($resourceProvider) {
|
|
||||||
// Don't strip trailing slashes from calculated URLs
|
|
||||||
$resourceProvider.defaults.stripTrailingSlashes = false;
|
|
||||||
}]);
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @param {string} url A parameterized URL template with parameters prefixed by `:` as in
|
|
||||||
* `/user/:username`. If you are using a URL with a port number (e.g.
|
|
||||||
* `http://example.com:8080/api`), it will be respected.
|
|
||||||
*
|
|
||||||
* If you are using a url with a suffix, just add the suffix, like this:
|
|
||||||
* `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')`
|
|
||||||
* or even `$resource('http://example.com/resource/:resource_id.:format')`
|
|
||||||
* If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be
|
|
||||||
* collapsed down to a single `.`. If you need this sequence to appear and not collapse then you
|
|
||||||
* can escape it with `/\.`.
|
|
||||||
*
|
|
||||||
* @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
|
|
||||||
* `actions` methods. If a parameter value is a function, it will be called every time
|
|
||||||
* a param value needs to be obtained for a request (unless the param was overridden). The
|
|
||||||
* function will be passed the current data value as an argument.
|
|
||||||
*
|
|
||||||
* Each key value in the parameter object is first bound to url template if present and then any
|
|
||||||
* excess keys are appended to the url search query after the `?`.
|
|
||||||
*
|
|
||||||
* Given a template `/path/:verb` and parameter `{verb: 'greet', salutation: 'Hello'}` results in
|
|
||||||
* URL `/path/greet?salutation=Hello`.
|
|
||||||
*
|
|
||||||
* If the parameter value is prefixed with `@`, then the value for that parameter will be
|
|
||||||
* extracted from the corresponding property on the `data` object (provided when calling actions
|
|
||||||
* with a request body).
|
|
||||||
* For example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of
|
|
||||||
* `someParam` will be `data.someProp`.
|
|
||||||
* Note that the parameter will be ignored, when calling a "GET" action method (i.e. an action
|
|
||||||
* method that does not accept a request body).
|
|
||||||
*
|
|
||||||
* @param {Object.<Object>=} actions Hash with declaration of custom actions that will be available
|
|
||||||
* in addition to the default set of resource actions (see below). If a custom action has the same
|
|
||||||
* key as a default action (e.g. `save`), then the default action will be *overwritten*, and not
|
|
||||||
* extended.
|
|
||||||
*
|
|
||||||
* The declaration should be created in the format of {@link ng.$http#usage $http.config}:
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* action1: {method:?, params:?, isArray:?, headers:?, ...},
|
|
||||||
* action2: {method:?, params:?, isArray:?, headers:?, ...},
|
|
||||||
* ...
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* Where:
|
|
||||||
*
|
|
||||||
* - **`action`** – {string} – The name of action. This name becomes the name of the method on
|
|
||||||
* your resource object.
|
|
||||||
* - **`method`** – {string} – Case insensitive HTTP method (e.g. `GET`, `POST`, `PUT`,
|
|
||||||
* `DELETE`, `JSONP`, etc).
|
|
||||||
* - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of
|
|
||||||
* the parameter value is a function, it will be called every time when a param value needs to
|
|
||||||
* be obtained for a request (unless the param was overridden). The function will be passed the
|
|
||||||
* current data value as an argument.
|
|
||||||
* - **`url`** – {string} – Action specific `url` override. The url templating is supported just
|
|
||||||
* like for the resource-level urls.
|
|
||||||
* - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
|
|
||||||
* see `returns` section.
|
|
||||||
* - **`transformRequest`** –
|
|
||||||
* `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
|
|
||||||
* Transform function or an array of such functions. The transform function takes the http
|
|
||||||
* request body and headers and returns its transformed (typically serialized) version.
|
|
||||||
* By default, transformRequest will contain one function that checks if the request data is
|
|
||||||
* an object and serializes it using `angular.toJson`. To prevent this behavior, set
|
|
||||||
* `transformRequest` to an empty array: `transformRequest: []`
|
|
||||||
* - **`transformResponse`** –
|
|
||||||
* `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
|
|
||||||
* Transform function or an array of such functions. The transform function takes the HTTP
|
|
||||||
* response body, headers and status and returns its transformed (typically deserialized)
|
|
||||||
* version.
|
|
||||||
* By default, transformResponse will contain one function that checks if the response looks
|
|
||||||
* like a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior,
|
|
||||||
* set `transformResponse` to an empty array: `transformResponse: []`
|
|
||||||
* - **`cache`** – `{boolean|Cache}` – A boolean value or object created with
|
|
||||||
* {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of the HTTP response.
|
|
||||||
* See {@link $http#caching $http Caching} for more information.
|
|
||||||
* - **`timeout`** – `{number}` – Timeout in milliseconds.<br />
|
|
||||||
* **Note:** In contrast to {@link ng.$http#usage $http.config}, {@link ng.$q promises} are
|
|
||||||
* **not** supported in `$resource`, because the same value would be used for multiple requests.
|
|
||||||
* If you are looking for a way to cancel requests, you should use the `cancellable` option.
|
|
||||||
* - **`cancellable`** – `{boolean}` – If true, the request made by a "non-instance" call will be
|
|
||||||
* cancelled (if not already completed) by calling `$cancelRequest()` on the call's return
|
|
||||||
* value. Calling `$cancelRequest()` for a non-cancellable or an already completed/cancelled
|
|
||||||
* request will have no effect.
|
|
||||||
* - **`withCredentials`** – `{boolean}` – Whether to set the `withCredentials` flag on the
|
|
||||||
* XHR object. See
|
|
||||||
* [XMLHttpRequest.withCredentials](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials)
|
|
||||||
* for more information.
|
|
||||||
* - **`responseType`** – `{string}` – See
|
|
||||||
* [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType).
|
|
||||||
* - **`interceptor`** – `{Object=}` – The interceptor object has four optional methods -
|
|
||||||
* `request`, `requestError`, `response`, and `responseError`. See
|
|
||||||
* {@link ng.$http#interceptors $http interceptors} for details. Note that
|
|
||||||
* `request`/`requestError` interceptors are applied before calling `$http`, thus before any
|
|
||||||
* global `$http` interceptors. Also, rejecting or throwing an error inside the `request`
|
|
||||||
* interceptor will result in calling the `responseError` interceptor.
|
|
||||||
* The resource instance or collection is available on the `resource` property of the
|
|
||||||
* `http response` object passed to `response`/`responseError` interceptors.
|
|
||||||
* Keep in mind that the associated promise will be resolved with the value returned by the
|
|
||||||
* response interceptors. Make sure you return an appropriate value and not the `response`
|
|
||||||
* object passed as input. For reference, the default `response` interceptor (which gets applied
|
|
||||||
* if you don't specify a custom one) returns `response.resource`.<br />
|
|
||||||
* See {@link ngResource.$resource#using-interceptors below} for an example of using
|
|
||||||
* interceptors in `$resource`.
|
|
||||||
* - **`hasBody`** – `{boolean}` – If true, then the request will have a body.
|
|
||||||
* If not specified, then only POST, PUT and PATCH requests will have a body. *
|
|
||||||
* @param {Object} options Hash with custom settings that should extend the
|
|
||||||
* default `$resourceProvider` behavior. The supported options are:
|
|
||||||
*
|
|
||||||
* - **`stripTrailingSlashes`** – {boolean} – If true then the trailing
|
|
||||||
* slashes from any calculated URL will be stripped. (Defaults to true.)
|
|
||||||
* - **`cancellable`** – {boolean} – If true, the request made by a "non-instance" call will be
|
|
||||||
* cancelled (if not already completed) by calling `$cancelRequest()` on the call's return value.
|
|
||||||
* This can be overwritten per action. (Defaults to false.)
|
|
||||||
*
|
|
||||||
* @returns {Object} A resource "class" object with methods for the default set of resource actions
|
|
||||||
* optionally extended with custom `actions`. The default set contains these actions:
|
|
||||||
* ```js
|
|
||||||
* {
|
|
||||||
* 'get': {method: 'GET'},
|
|
||||||
* 'save': {method: 'POST'},
|
|
||||||
* 'query': {method: 'GET', isArray: true},
|
|
||||||
* 'remove': {method: 'DELETE'},
|
|
||||||
* 'delete': {method: 'DELETE'}
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Calling these methods invoke {@link ng.$http} with the specified http method, destination and
|
|
||||||
* parameters. When the data is returned from the server then the object is an instance of the
|
|
||||||
* resource class. The actions `save`, `remove` and `delete` are available on it as methods with
|
|
||||||
* the `$` prefix. This allows you to easily perform CRUD operations (create, read, update,
|
|
||||||
* delete) on server-side data like this:
|
|
||||||
* ```js
|
|
||||||
* var User = $resource('/user/:userId', {userId: '@id'});
|
|
||||||
* User.get({userId: 123}).$promise.then(function(user) {
|
|
||||||
* user.abc = true;
|
|
||||||
* user.$save();
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* It is important to realize that invoking a `$resource` object method immediately returns an
|
|
||||||
* empty reference (object or array depending on `isArray`). Once the data is returned from the
|
|
||||||
* server the existing reference is populated with the actual data. This is a useful trick since
|
|
||||||
* usually the resource is assigned to a model which is then rendered by the view. Having an empty
|
|
||||||
* object results in no rendering, once the data arrives from the server then the object is
|
|
||||||
* populated with the data and the view automatically re-renders itself showing the new data. This
|
|
||||||
* means that in most cases one never has to write a callback function for the action methods.
|
|
||||||
*
|
|
||||||
* The action methods on the class object or instance object can be invoked with the following
|
|
||||||
* parameters:
|
|
||||||
*
|
|
||||||
* - "class" actions without a body: `Resource.action([parameters], [success], [error])`
|
|
||||||
* - "class" actions with a body: `Resource.action([parameters], postData, [success], [error])`
|
|
||||||
* - instance actions: `instance.$action([parameters], [success], [error])`
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* When calling instance methods, the instance itself is used as the request body (if the action
|
|
||||||
* should have a body). By default, only actions using `POST`, `PUT` or `PATCH` have request
|
|
||||||
* bodies, but you can use the `hasBody` configuration option to specify whether an action
|
|
||||||
* should have a body or not (regardless of its HTTP method).
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Success callback is called with (value (Object|Array), responseHeaders (Function),
|
|
||||||
* status (number), statusText (string)) arguments, where `value` is the populated resource
|
|
||||||
* instance or collection object. The error callback is called with (httpResponse) argument.
|
|
||||||
*
|
|
||||||
* Class actions return an empty instance (with the additional properties listed below).
|
|
||||||
* Instance actions return a promise for the operation.
|
|
||||||
*
|
|
||||||
* The Resource instances and collections have these additional properties:
|
|
||||||
*
|
|
||||||
* - `$promise`: The {@link ng.$q promise} of the original server interaction that created this
|
|
||||||
* instance or collection.
|
|
||||||
*
|
|
||||||
* On success, the promise is resolved with the same resource instance or collection object,
|
|
||||||
* updated with data from server. This makes it easy to use in the
|
|
||||||
* {@link ngRoute.$routeProvider `resolve` section of `$routeProvider.when()`} to defer view
|
|
||||||
* rendering until the resource(s) are loaded.
|
|
||||||
*
|
|
||||||
* On failure, the promise is rejected with the {@link ng.$http http response} object.
|
|
||||||
*
|
|
||||||
* If an interceptor object was provided, the promise will instead be resolved with the value
|
|
||||||
* returned by the response interceptor (on success) or responceError interceptor (on failure).
|
|
||||||
*
|
|
||||||
* - `$resolved`: `true` after first server interaction is completed (either with success or
|
|
||||||
* rejection), `false` before that. Knowing if the Resource has been resolved is useful in
|
|
||||||
* data-binding. If there is a response/responseError interceptor and it returns a promise,
|
|
||||||
* `$resolved` will wait for that too.
|
|
||||||
*
|
|
||||||
* The Resource instances and collections have these additional methods:
|
|
||||||
*
|
|
||||||
* - `$cancelRequest`: If there is a cancellable, pending request related to the instance or
|
|
||||||
* collection, calling this method will abort the request.
|
|
||||||
*
|
|
||||||
* The Resource instances have these additional methods:
|
|
||||||
*
|
|
||||||
* - `toJSON`: It returns a simple object without any of the extra properties added as part of
|
|
||||||
* the Resource API. This object can be serialized through {@link angular.toJson} safely
|
|
||||||
* without attaching AngularJS-specific fields. Notice that `JSON.stringify` (and
|
|
||||||
* `angular.toJson`) automatically use this method when serializing a Resource instance
|
|
||||||
* (see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON%28%29_behavior)).
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ### Basic usage
|
|
||||||
*
|
|
||||||
```js
|
|
||||||
// Define a CreditCard class
|
|
||||||
var CreditCard = $resource('/users/:userId/cards/:cardId',
|
|
||||||
{userId: 123, cardId: '@id'}, {
|
|
||||||
charge: {method: 'POST', params: {charge: true}}
|
|
||||||
});
|
|
||||||
|
|
||||||
// We can retrieve a collection from the server
|
|
||||||
var cards = CreditCard.query();
|
|
||||||
// GET: /users/123/cards
|
|
||||||
// server returns: [{id: 456, number: '1234', name: 'Smith'}]
|
|
||||||
|
|
||||||
// Wait for the request to complete
|
|
||||||
cards.$promise.then(function() {
|
|
||||||
var card = cards[0];
|
|
||||||
|
|
||||||
// Each item is an instance of CreditCard
|
|
||||||
expect(card instanceof CreditCard).toEqual(true);
|
|
||||||
|
|
||||||
// Non-GET methods are mapped onto the instances
|
|
||||||
card.name = 'J. Smith';
|
|
||||||
card.$save();
|
|
||||||
// POST: /users/123/cards/456 {id: 456, number: '1234', name: 'J. Smith'}
|
|
||||||
// server returns: {id: 456, number: '1234', name: 'J. Smith'}
|
|
||||||
|
|
||||||
// Our custom method is mapped as well (since it uses POST)
|
|
||||||
card.$charge({amount: 9.99});
|
|
||||||
// POST: /users/123/cards/456?amount=9.99&charge=true {id: 456, number: '1234', name: 'J. Smith'}
|
|
||||||
});
|
|
||||||
|
|
||||||
// We can create an instance as well
|
|
||||||
var newCard = new CreditCard({number: '0123'});
|
|
||||||
newCard.name = 'Mike Smith';
|
|
||||||
|
|
||||||
var savePromise = newCard.$save();
|
|
||||||
// POST: /users/123/cards {number: '0123', name: 'Mike Smith'}
|
|
||||||
// server returns: {id: 789, number: '0123', name: 'Mike Smith'}
|
|
||||||
|
|
||||||
savePromise.then(function() {
|
|
||||||
// Once the promise is resolved, the created instance
|
|
||||||
// is populated with the data returned by the server
|
|
||||||
expect(newCard.id).toEqual(789);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
*
|
|
||||||
* The object returned from a call to `$resource` is a resource "class" which has one "static"
|
|
||||||
* method for each action in the definition.
|
|
||||||
*
|
|
||||||
* Calling these methods invokes `$http` on the `url` template with the given HTTP `method`,
|
|
||||||
* `params` and `headers`.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ### Accessing the response
|
|
||||||
*
|
|
||||||
* When the data is returned from the server then the object is an instance of the resource type and
|
|
||||||
* all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
|
|
||||||
* operations (create, read, update, delete) on server-side data.
|
|
||||||
*
|
|
||||||
```js
|
|
||||||
var User = $resource('/users/:userId', {userId: '@id'});
|
|
||||||
User.get({userId: 123}).$promise.then(function(user) {
|
|
||||||
user.abc = true;
|
|
||||||
user.$save();
|
|
||||||
});
|
|
||||||
```
|
|
||||||
*
|
|
||||||
* It's worth noting that the success callback for `get`, `query` and other methods gets called with
|
|
||||||
* the resource instance (populated with the data that came from the server) as well as an `$http`
|
|
||||||
* header getter function, the HTTP status code and the response status text. So one could rewrite
|
|
||||||
* the above example and get access to HTTP headers as follows:
|
|
||||||
*
|
|
||||||
```js
|
|
||||||
var User = $resource('/users/:userId', {userId: '@id'});
|
|
||||||
User.get({userId: 123}, function(user, getResponseHeaders) {
|
|
||||||
user.abc = true;
|
|
||||||
user.$save(function(user, putResponseHeaders) {
|
|
||||||
// `user` => saved `User` object
|
|
||||||
// `putResponseHeaders` => `$http` header getter
|
|
||||||
});
|
|
||||||
});
|
|
||||||
```
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ### Creating custom actions
|
|
||||||
*
|
|
||||||
* In this example we create a custom method on our resource to make a PUT request:
|
|
||||||
*
|
|
||||||
```js
|
|
||||||
var app = angular.module('app', ['ngResource']);
|
|
||||||
|
|
||||||
// Some APIs expect a PUT request in the format URL/object/ID
|
|
||||||
// Here we are creating an 'update' method
|
|
||||||
app.factory('Notes', ['$resource', function($resource) {
|
|
||||||
return $resource('/notes/:id', {id: '@id'}, {
|
|
||||||
update: {method: 'PUT'}
|
|
||||||
});
|
|
||||||
}]);
|
|
||||||
|
|
||||||
// In our controller we get the ID from the URL using `$location`
|
|
||||||
app.controller('NotesCtrl', ['$location', 'Notes', function($location, Notes) {
|
|
||||||
// First, retrieve the corresponding `Note` object from the server
|
|
||||||
// (Assuming a URL of the form `.../notes?id=XYZ`)
|
|
||||||
var noteId = $location.search().id;
|
|
||||||
var note = Notes.get({id: noteId});
|
|
||||||
|
|
||||||
note.$promise.then(function() {
|
|
||||||
note.content = 'Hello, world!';
|
|
||||||
|
|
||||||
// Now call `update` to save the changes on the server
|
|
||||||
Notes.update(note);
|
|
||||||
// This will PUT /notes/ID with the note object as the request payload
|
|
||||||
|
|
||||||
// Since `update` is a non-GET method, it will also be available on the instance
|
|
||||||
// (prefixed with `$`), so we could replace the `Note.update()` call with:
|
|
||||||
//note.$update();
|
|
||||||
});
|
|
||||||
}]);
|
|
||||||
```
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ### Cancelling requests
|
|
||||||
*
|
|
||||||
* If an action's configuration specifies that it is cancellable, you can cancel the request related
|
|
||||||
* to an instance or collection (as long as it is a result of a "non-instance" call):
|
|
||||||
*
|
|
||||||
```js
|
|
||||||
// ...defining the `Hotel` resource...
|
|
||||||
var Hotel = $resource('/api/hotels/:id', {id: '@id'}, {
|
|
||||||
// Let's make the `query()` method cancellable
|
|
||||||
query: {method: 'get', isArray: true, cancellable: true}
|
|
||||||
});
|
|
||||||
|
|
||||||
// ...somewhere in the PlanVacationController...
|
|
||||||
...
|
|
||||||
this.onDestinationChanged = function onDestinationChanged(destination) {
|
|
||||||
// We don't care about any pending request for hotels
|
|
||||||
// in a different destination any more
|
|
||||||
if (this.availableHotels) {
|
|
||||||
this.availableHotels.$cancelRequest();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let's query for hotels in `destination`
|
|
||||||
// (calls: /api/hotels?location=<destination>)
|
|
||||||
this.availableHotels = Hotel.query({location: destination});
|
|
||||||
};
|
|
||||||
```
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ### Using interceptors
|
|
||||||
*
|
|
||||||
* You can use interceptors to transform the request or response, perform additional operations, and
|
|
||||||
* modify the returned instance/collection. The following example, uses `request` and `response`
|
|
||||||
* interceptors to augment the returned instance with additional info:
|
|
||||||
*
|
|
||||||
```js
|
|
||||||
var Thing = $resource('/api/things/:id', {id: '@id'}, {
|
|
||||||
save: {
|
|
||||||
method: 'POST',
|
|
||||||
interceptor: {
|
|
||||||
request: function(config) {
|
|
||||||
// Before the request is sent out, store a timestamp on the request config
|
|
||||||
config.requestTimestamp = Date.now();
|
|
||||||
return config;
|
|
||||||
},
|
|
||||||
response: function(response) {
|
|
||||||
// Get the instance from the response object
|
|
||||||
var instance = response.resource;
|
|
||||||
|
|
||||||
// Augment the instance with a custom `saveLatency` property, computed as the time
|
|
||||||
// between sending the request and receiving the response.
|
|
||||||
instance.saveLatency = Date.now() - response.config.requestTimestamp;
|
|
||||||
|
|
||||||
// Return the instance
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Thing.save({foo: 'bar'}).$promise.then(function(thing) {
|
|
||||||
console.log('That thing was saved in ' + thing.saveLatency + 'ms.');
|
|
||||||
});
|
|
||||||
```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
angular.module('ngResource', ['ng']).
|
|
||||||
info({ angularVersion: '1.8.0' }).
|
|
||||||
provider('$resource', function ResourceProvider() {
|
|
||||||
var PROTOCOL_AND_IPV6_REGEX = /^https?:\/\/\[[^\]]*][^/]*/;
|
|
||||||
|
|
||||||
var provider = this;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc property
|
|
||||||
* @name $resourceProvider#defaults
|
|
||||||
* @description
|
|
||||||
* Object containing default options used when creating `$resource` instances.
|
|
||||||
*
|
|
||||||
* The default values satisfy a wide range of usecases, but you may choose to overwrite any of
|
|
||||||
* them to further customize your instances. The available properties are:
|
|
||||||
*
|
|
||||||
* - **stripTrailingSlashes** – `{boolean}` – If true, then the trailing slashes from any
|
|
||||||
* calculated URL will be stripped.<br />
|
|
||||||
* (Defaults to true.)
|
|
||||||
* - **cancellable** – `{boolean}` – If true, the request made by a "non-instance" call will be
|
|
||||||
* cancelled (if not already completed) by calling `$cancelRequest()` on the call's return
|
|
||||||
* value. For more details, see {@link ngResource.$resource}. This can be overwritten per
|
|
||||||
* resource class or action.<br />
|
|
||||||
* (Defaults to false.)
|
|
||||||
* - **actions** - `{Object.<Object>}` - A hash with default actions declarations. Actions are
|
|
||||||
* high-level methods corresponding to RESTful actions/methods on resources. An action may
|
|
||||||
* specify what HTTP method to use, what URL to hit, if the return value will be a single
|
|
||||||
* object or a collection (array) of objects etc. For more details, see
|
|
||||||
* {@link ngResource.$resource}. The actions can also be enhanced or overwritten per resource
|
|
||||||
* class.<br />
|
|
||||||
* The default actions are:
|
|
||||||
* ```js
|
|
||||||
* {
|
|
||||||
* get: {method: 'GET'},
|
|
||||||
* save: {method: 'POST'},
|
|
||||||
* query: {method: 'GET', isArray: true},
|
|
||||||
* remove: {method: 'DELETE'},
|
|
||||||
* delete: {method: 'DELETE'}
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* #### Example
|
|
||||||
*
|
|
||||||
* For example, you can specify a new `update` action that uses the `PUT` HTTP verb:
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
* angular.
|
|
||||||
* module('myApp').
|
|
||||||
* config(['$resourceProvider', function ($resourceProvider) {
|
|
||||||
* $resourceProvider.defaults.actions.update = {
|
|
||||||
* method: 'PUT'
|
|
||||||
* };
|
|
||||||
* }]);
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Or you can even overwrite the whole `actions` list and specify your own:
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
* angular.
|
|
||||||
* module('myApp').
|
|
||||||
* config(['$resourceProvider', function ($resourceProvider) {
|
|
||||||
* $resourceProvider.defaults.actions = {
|
|
||||||
* create: {method: 'POST'},
|
|
||||||
* get: {method: 'GET'},
|
|
||||||
* getAll: {method: 'GET', isArray:true},
|
|
||||||
* update: {method: 'PUT'},
|
|
||||||
* delete: {method: 'DELETE'}
|
|
||||||
* };
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
this.defaults = {
|
|
||||||
// Strip slashes by default
|
|
||||||
stripTrailingSlashes: true,
|
|
||||||
|
|
||||||
// Make non-instance requests cancellable (via `$cancelRequest()`)
|
|
||||||
cancellable: false,
|
|
||||||
|
|
||||||
// Default actions configuration
|
|
||||||
actions: {
|
|
||||||
'get': {method: 'GET'},
|
|
||||||
'save': {method: 'POST'},
|
|
||||||
'query': {method: 'GET', isArray: true},
|
|
||||||
'remove': {method: 'DELETE'},
|
|
||||||
'delete': {method: 'DELETE'}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.$get = ['$http', '$log', '$q', '$timeout', function($http, $log, $q, $timeout) {
|
|
||||||
|
|
||||||
var noop = angular.noop,
|
|
||||||
forEach = angular.forEach,
|
|
||||||
extend = angular.extend,
|
|
||||||
copy = angular.copy,
|
|
||||||
isArray = angular.isArray,
|
|
||||||
isDefined = angular.isDefined,
|
|
||||||
isFunction = angular.isFunction,
|
|
||||||
isNumber = angular.isNumber,
|
|
||||||
encodeUriQuery = angular.$$encodeUriQuery,
|
|
||||||
encodeUriSegment = angular.$$encodeUriSegment;
|
|
||||||
|
|
||||||
function Route(template, defaults) {
|
|
||||||
this.template = template;
|
|
||||||
this.defaults = extend({}, provider.defaults, defaults);
|
|
||||||
this.urlParams = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Route.prototype = {
|
|
||||||
setUrlParams: function(config, params, actionUrl) {
|
|
||||||
var self = this,
|
|
||||||
url = actionUrl || self.template,
|
|
||||||
val,
|
|
||||||
encodedVal,
|
|
||||||
protocolAndIpv6 = '';
|
|
||||||
|
|
||||||
var urlParams = self.urlParams = Object.create(null);
|
|
||||||
forEach(url.split(/\W/), function(param) {
|
|
||||||
if (param === 'hasOwnProperty') {
|
|
||||||
throw $resourceMinErr('badname', 'hasOwnProperty is not a valid parameter name.');
|
|
||||||
}
|
|
||||||
if (!(new RegExp('^\\d+$').test(param)) && param &&
|
|
||||||
(new RegExp('(^|[^\\\\]):' + param + '(\\W|$)').test(url))) {
|
|
||||||
urlParams[param] = {
|
|
||||||
isQueryParamValue: (new RegExp('\\?.*=:' + param + '(?:\\W|$)')).test(url)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
url = url.replace(/\\:/g, ':');
|
|
||||||
url = url.replace(PROTOCOL_AND_IPV6_REGEX, function(match) {
|
|
||||||
protocolAndIpv6 = match;
|
|
||||||
return '';
|
|
||||||
});
|
|
||||||
|
|
||||||
params = params || {};
|
|
||||||
forEach(self.urlParams, function(paramInfo, urlParam) {
|
|
||||||
val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
|
|
||||||
if (isDefined(val) && val !== null) {
|
|
||||||
if (paramInfo.isQueryParamValue) {
|
|
||||||
encodedVal = encodeUriQuery(val, true);
|
|
||||||
} else {
|
|
||||||
encodedVal = encodeUriSegment(val);
|
|
||||||
}
|
|
||||||
url = url.replace(new RegExp(':' + urlParam + '(\\W|$)', 'g'), function(match, p1) {
|
|
||||||
return encodedVal + p1;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
url = url.replace(new RegExp('(/?):' + urlParam + '(\\W|$)', 'g'), function(match,
|
|
||||||
leadingSlashes, tail) {
|
|
||||||
if (tail.charAt(0) === '/') {
|
|
||||||
return tail;
|
|
||||||
} else {
|
|
||||||
return leadingSlashes + tail;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// strip trailing slashes and set the url (unless this behavior is specifically disabled)
|
|
||||||
if (self.defaults.stripTrailingSlashes) {
|
|
||||||
url = url.replace(/\/+$/, '') || '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collapse `/.` if found in the last URL path segment before the query.
|
|
||||||
// E.g. `http://url.com/id/.format?q=x` becomes `http://url.com/id.format?q=x`.
|
|
||||||
url = url.replace(/\/\.(?=\w+($|\?))/, '.');
|
|
||||||
// Replace escaped `/\.` with `/.`.
|
|
||||||
// (If `\.` comes from a param value, it will be encoded as `%5C.`.)
|
|
||||||
config.url = protocolAndIpv6 + url.replace(/\/(\\|%5C)\./, '/.');
|
|
||||||
|
|
||||||
|
|
||||||
// set params - delegate param encoding to $http
|
|
||||||
forEach(params, function(value, key) {
|
|
||||||
if (!self.urlParams[key]) {
|
|
||||||
config.params = config.params || {};
|
|
||||||
config.params[key] = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
function resourceFactory(url, paramDefaults, actions, options) {
|
|
||||||
var route = new Route(url, options);
|
|
||||||
|
|
||||||
actions = extend({}, provider.defaults.actions, actions);
|
|
||||||
|
|
||||||
function extractParams(data, actionParams) {
|
|
||||||
var ids = {};
|
|
||||||
actionParams = extend({}, paramDefaults, actionParams);
|
|
||||||
forEach(actionParams, function(value, key) {
|
|
||||||
if (isFunction(value)) { value = value(data); }
|
|
||||||
ids[key] = value && value.charAt && value.charAt(0) === '@' ?
|
|
||||||
lookupDottedPath(data, value.substr(1)) : value;
|
|
||||||
});
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
function defaultResponseInterceptor(response) {
|
|
||||||
return response.resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Resource(value) {
|
|
||||||
shallowClearAndCopy(value || {}, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
Resource.prototype.toJSON = function() {
|
|
||||||
var data = extend({}, this);
|
|
||||||
delete data.$promise;
|
|
||||||
delete data.$resolved;
|
|
||||||
delete data.$cancelRequest;
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
forEach(actions, function(action, name) {
|
|
||||||
var hasBody = action.hasBody === true || (action.hasBody !== false && /^(POST|PUT|PATCH)$/i.test(action.method));
|
|
||||||
var numericTimeout = action.timeout;
|
|
||||||
var cancellable = isDefined(action.cancellable) ?
|
|
||||||
action.cancellable : route.defaults.cancellable;
|
|
||||||
|
|
||||||
if (numericTimeout && !isNumber(numericTimeout)) {
|
|
||||||
$log.debug('ngResource:\n' +
|
|
||||||
' Only numeric values are allowed as `timeout`.\n' +
|
|
||||||
' Promises are not supported in $resource, because the same value would ' +
|
|
||||||
'be used for multiple requests. If you are looking for a way to cancel ' +
|
|
||||||
'requests, you should use the `cancellable` option.');
|
|
||||||
delete action.timeout;
|
|
||||||
numericTimeout = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Resource[name] = function(a1, a2, a3, a4) {
|
|
||||||
var params = {}, data, onSuccess, onError;
|
|
||||||
|
|
||||||
switch (arguments.length) {
|
|
||||||
case 4:
|
|
||||||
onError = a4;
|
|
||||||
onSuccess = a3;
|
|
||||||
// falls through
|
|
||||||
case 3:
|
|
||||||
case 2:
|
|
||||||
if (isFunction(a2)) {
|
|
||||||
if (isFunction(a1)) {
|
|
||||||
onSuccess = a1;
|
|
||||||
onError = a2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
onSuccess = a2;
|
|
||||||
onError = a3;
|
|
||||||
// falls through
|
|
||||||
} else {
|
|
||||||
params = a1;
|
|
||||||
data = a2;
|
|
||||||
onSuccess = a3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// falls through
|
|
||||||
case 1:
|
|
||||||
if (isFunction(a1)) onSuccess = a1;
|
|
||||||
else if (hasBody) data = a1;
|
|
||||||
else params = a1;
|
|
||||||
break;
|
|
||||||
case 0: break;
|
|
||||||
default:
|
|
||||||
throw $resourceMinErr('badargs',
|
|
||||||
'Expected up to 4 arguments [params, data, success, error], got {0} arguments',
|
|
||||||
arguments.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
var isInstanceCall = this instanceof Resource;
|
|
||||||
var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
|
|
||||||
var httpConfig = {};
|
|
||||||
var requestInterceptor = action.interceptor && action.interceptor.request || undefined;
|
|
||||||
var requestErrorInterceptor = action.interceptor && action.interceptor.requestError ||
|
|
||||||
undefined;
|
|
||||||
var responseInterceptor = action.interceptor && action.interceptor.response ||
|
|
||||||
defaultResponseInterceptor;
|
|
||||||
var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
|
|
||||||
$q.reject;
|
|
||||||
var successCallback = onSuccess ? function(val) {
|
|
||||||
onSuccess(val, response.headers, response.status, response.statusText);
|
|
||||||
} : undefined;
|
|
||||||
var errorCallback = onError || undefined;
|
|
||||||
var timeoutDeferred;
|
|
||||||
var numericTimeoutPromise;
|
|
||||||
var response;
|
|
||||||
|
|
||||||
forEach(action, function(value, key) {
|
|
||||||
switch (key) {
|
|
||||||
default:
|
|
||||||
httpConfig[key] = copy(value);
|
|
||||||
break;
|
|
||||||
case 'params':
|
|
||||||
case 'isArray':
|
|
||||||
case 'interceptor':
|
|
||||||
case 'cancellable':
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!isInstanceCall && cancellable) {
|
|
||||||
timeoutDeferred = $q.defer();
|
|
||||||
httpConfig.timeout = timeoutDeferred.promise;
|
|
||||||
|
|
||||||
if (numericTimeout) {
|
|
||||||
numericTimeoutPromise = $timeout(timeoutDeferred.resolve, numericTimeout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasBody) httpConfig.data = data;
|
|
||||||
route.setUrlParams(httpConfig,
|
|
||||||
extend({}, extractParams(data, action.params || {}), params),
|
|
||||||
action.url);
|
|
||||||
|
|
||||||
// Start the promise chain
|
|
||||||
var promise = $q.
|
|
||||||
resolve(httpConfig).
|
|
||||||
then(requestInterceptor).
|
|
||||||
catch(requestErrorInterceptor).
|
|
||||||
then($http);
|
|
||||||
|
|
||||||
promise = promise.then(function(resp) {
|
|
||||||
var data = resp.data;
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
// Need to convert action.isArray to boolean in case it is undefined
|
|
||||||
if (isArray(data) !== (!!action.isArray)) {
|
|
||||||
throw $resourceMinErr('badcfg',
|
|
||||||
'Error in resource configuration for action `{0}`. Expected response to ' +
|
|
||||||
'contain an {1} but got an {2} (Request: {3} {4})', name, action.isArray ? 'array' : 'object',
|
|
||||||
isArray(data) ? 'array' : 'object', httpConfig.method, httpConfig.url);
|
|
||||||
}
|
|
||||||
if (action.isArray) {
|
|
||||||
value.length = 0;
|
|
||||||
forEach(data, function(item) {
|
|
||||||
if (typeof item === 'object') {
|
|
||||||
value.push(new Resource(item));
|
|
||||||
} else {
|
|
||||||
// Valid JSON values may be string literals, and these should not be converted
|
|
||||||
// into objects. These items will not have access to the Resource prototype
|
|
||||||
// methods, but unfortunately there
|
|
||||||
value.push(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
var promise = value.$promise; // Save the promise
|
|
||||||
shallowClearAndCopy(data, value);
|
|
||||||
value.$promise = promise; // Restore the promise
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.resource = value;
|
|
||||||
response = resp;
|
|
||||||
return responseInterceptor(resp);
|
|
||||||
}, function(rejectionOrResponse) {
|
|
||||||
rejectionOrResponse.resource = value;
|
|
||||||
response = rejectionOrResponse;
|
|
||||||
return responseErrorInterceptor(rejectionOrResponse);
|
|
||||||
});
|
|
||||||
|
|
||||||
promise = promise['finally'](function() {
|
|
||||||
value.$resolved = true;
|
|
||||||
if (!isInstanceCall && cancellable) {
|
|
||||||
value.$cancelRequest = noop;
|
|
||||||
$timeout.cancel(numericTimeoutPromise);
|
|
||||||
timeoutDeferred = numericTimeoutPromise = httpConfig.timeout = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Run the `success`/`error` callbacks, but do not let them affect the returned promise.
|
|
||||||
promise.then(successCallback, errorCallback);
|
|
||||||
|
|
||||||
if (!isInstanceCall) {
|
|
||||||
// we are creating instance / collection
|
|
||||||
// - set the initial promise
|
|
||||||
// - return the instance / collection
|
|
||||||
value.$promise = promise;
|
|
||||||
value.$resolved = false;
|
|
||||||
if (cancellable) value.$cancelRequest = cancelRequest;
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// instance call
|
|
||||||
return promise;
|
|
||||||
|
|
||||||
function cancelRequest(value) {
|
|
||||||
promise.catch(noop);
|
|
||||||
if (timeoutDeferred !== null) {
|
|
||||||
timeoutDeferred.resolve(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Resource.prototype['$' + name] = function(params, success, error) {
|
|
||||||
if (isFunction(params)) {
|
|
||||||
error = success; success = params; params = {};
|
|
||||||
}
|
|
||||||
var result = Resource[name].call(this, params, this, success, error);
|
|
||||||
return result.$promise || result;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return Resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
return resourceFactory;
|
|
||||||
}];
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
})(window, window.angular);
|
|
|
@ -1,15 +0,0 @@
|
||||||
/*
|
|
||||||
AngularJS v1.8.0
|
|
||||||
(c) 2010-2020 Google, Inc. http://angularjs.org
|
|
||||||
License: MIT
|
|
||||||
*/
|
|
||||||
(function(T,a){'use strict';function M(m,f){f=f||{};a.forEach(f,function(a,d){delete f[d]});for(var d in m)!m.hasOwnProperty(d)||"$"===d.charAt(0)&&"$"===d.charAt(1)||(f[d]=m[d]);return f}var B=a.$$minErr("$resource"),H=/^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;a.module("ngResource",["ng"]).info({angularVersion:"1.8.0"}).provider("$resource",function(){var m=/^https?:\/\/\[[^\]]*][^/]*/,f=this;this.defaults={stripTrailingSlashes:!0,cancellable:!1,actions:{get:{method:"GET"},save:{method:"POST"},query:{method:"GET",
|
|
||||||
isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}}};this.$get=["$http","$log","$q","$timeout",function(d,F,G,N){function C(a,d){this.template=a;this.defaults=n({},f.defaults,d);this.urlParams={}}var O=a.noop,r=a.forEach,n=a.extend,R=a.copy,P=a.isArray,D=a.isDefined,x=a.isFunction,I=a.isNumber,y=a.$$encodeUriQuery,S=a.$$encodeUriSegment;C.prototype={setUrlParams:function(a,d,f){var g=this,c=f||g.template,s,h,n="",b=g.urlParams=Object.create(null);r(c.split(/\W/),function(a){if("hasOwnProperty"===
|
|
||||||
a)throw B("badname");!/^\d+$/.test(a)&&a&&(new RegExp("(^|[^\\\\]):"+a+"(\\W|$)")).test(c)&&(b[a]={isQueryParamValue:(new RegExp("\\?.*=:"+a+"(?:\\W|$)")).test(c)})});c=c.replace(/\\:/g,":");c=c.replace(m,function(b){n=b;return""});d=d||{};r(g.urlParams,function(b,a){s=d.hasOwnProperty(a)?d[a]:g.defaults[a];D(s)&&null!==s?(h=b.isQueryParamValue?y(s,!0):S(s),c=c.replace(new RegExp(":"+a+"(\\W|$)","g"),function(b,a){return h+a})):c=c.replace(new RegExp("(/?):"+a+"(\\W|$)","g"),function(b,a,e){return"/"===
|
|
||||||
e.charAt(0)?e:a+e})});g.defaults.stripTrailingSlashes&&(c=c.replace(/\/+$/,"")||"/");c=c.replace(/\/\.(?=\w+($|\?))/,".");a.url=n+c.replace(/\/(\\|%5C)\./,"/.");r(d,function(b,c){g.urlParams[c]||(a.params=a.params||{},a.params[c]=b)})}};return function(m,y,z,g){function c(b,c){var d={};c=n({},y,c);r(c,function(c,f){x(c)&&(c=c(b));var e;if(c&&c.charAt&&"@"===c.charAt(0)){e=b;var k=c.substr(1);if(null==k||""===k||"hasOwnProperty"===k||!H.test("."+k))throw B("badmember",k);for(var k=k.split("."),h=0,
|
|
||||||
n=k.length;h<n&&a.isDefined(e);h++){var g=k[h];e=null!==e?e[g]:void 0}}else e=c;d[f]=e});return d}function s(b){return b.resource}function h(b){M(b||{},this)}var Q=new C(m,g);z=n({},f.defaults.actions,z);h.prototype.toJSON=function(){var b=n({},this);delete b.$promise;delete b.$resolved;delete b.$cancelRequest;return b};r(z,function(b,a){var f=!0===b.hasBody||!1!==b.hasBody&&/^(POST|PUT|PATCH)$/i.test(b.method),g=b.timeout,m=D(b.cancellable)?b.cancellable:Q.defaults.cancellable;g&&!I(g)&&(F.debug("ngResource:\n Only numeric values are allowed as `timeout`.\n Promises are not supported in $resource, because the same value would be used for multiple requests. If you are looking for a way to cancel requests, you should use the `cancellable` option."),
|
|
||||||
delete b.timeout,g=null);h[a]=function(e,k,J,y){function z(a){p.catch(O);null!==u&&u.resolve(a)}var K={},v,t,w;switch(arguments.length){case 4:w=y,t=J;case 3:case 2:if(x(k)){if(x(e)){t=e;w=k;break}t=k;w=J}else{K=e;v=k;t=J;break}case 1:x(e)?t=e:f?v=e:K=e;break;case 0:break;default:throw B("badargs",arguments.length);}var E=this instanceof h,l=E?v:b.isArray?[]:new h(v),q={},C=b.interceptor&&b.interceptor.request||void 0,D=b.interceptor&&b.interceptor.requestError||void 0,F=b.interceptor&&b.interceptor.response||
|
|
||||||
s,H=b.interceptor&&b.interceptor.responseError||G.reject,I=t?function(a){t(a,A.headers,A.status,A.statusText)}:void 0;w=w||void 0;var u,L,A;r(b,function(a,b){switch(b){default:q[b]=R(a);case "params":case "isArray":case "interceptor":case "cancellable":}});!E&&m&&(u=G.defer(),q.timeout=u.promise,g&&(L=N(u.resolve,g)));f&&(q.data=v);Q.setUrlParams(q,n({},c(v,b.params||{}),K),b.url);var p=G.resolve(q).then(C).catch(D).then(d),p=p.then(function(c){var e=c.data;if(e){if(P(e)!==!!b.isArray)throw B("badcfg",
|
|
||||||
a,b.isArray?"array":"object",P(e)?"array":"object",q.method,q.url);if(b.isArray)l.length=0,r(e,function(a){"object"===typeof a?l.push(new h(a)):l.push(a)});else{var d=l.$promise;M(e,l);l.$promise=d}}c.resource=l;A=c;return F(c)},function(a){a.resource=l;A=a;return H(a)}),p=p["finally"](function(){l.$resolved=!0;!E&&m&&(l.$cancelRequest=O,N.cancel(L),u=L=q.timeout=null)});p.then(I,w);return E?p:(l.$promise=p,l.$resolved=!1,m&&(l.$cancelRequest=z),l)};h.prototype["$"+a]=function(b,c,d){x(b)&&(d=c,c=
|
|
||||||
b,b={});b=h[a].call(this,b,this,c,d);return b.$promise||b}});return h}}]})})(window,window.angular);
|
|
||||||
//# sourceMappingURL=angular-resource.min.js.map
|
|
File diff suppressed because one or more lines are too long
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"name": "angular-resource",
|
|
||||||
"version": "1.8.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "./angular-resource.js",
|
|
||||||
"ignore": [],
|
|
||||||
"dependencies": {
|
|
||||||
"angular": "1.8.0"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
require('./angular-resource');
|
|
||||||
module.exports = 'ngResource';
|
|
|
@ -1,63 +0,0 @@
|
||||||
{
|
|
||||||
"_from": "angular-resource@1.8.0",
|
|
||||||
"_id": "angular-resource@1.8.0",
|
|
||||||
"_inBundle": false,
|
|
||||||
"_integrity": "sha512-9woUq3kDwoT7R6SjKX8vaJMhOplYBm9sqRAxKgDhDIdPyA8iBowqQIusf9+8Q+z/HlXb8ZXvKspJyKXrxmKdvg==",
|
|
||||||
"_location": "/angular-resource",
|
|
||||||
"_phantomChildren": {},
|
|
||||||
"_requested": {
|
|
||||||
"type": "version",
|
|
||||||
"registry": true,
|
|
||||||
"raw": "angular-resource@1.8.0",
|
|
||||||
"name": "angular-resource",
|
|
||||||
"escapedName": "angular-resource",
|
|
||||||
"rawSpec": "1.8.0",
|
|
||||||
"saveSpec": null,
|
|
||||||
"fetchSpec": "1.8.0"
|
|
||||||
},
|
|
||||||
"_requiredBy": [
|
|
||||||
"/"
|
|
||||||
],
|
|
||||||
"_resolved": "https://registry.npmjs.org/angular-resource/-/angular-resource-1.8.0.tgz",
|
|
||||||
"_shasum": "578ef122e7cb7bcc6c0ad6c2451dc3d27fd570ba",
|
|
||||||
"_spec": "angular-resource@1.8.0",
|
|
||||||
"_where": "/home/abstractj/github/keycloak/themes/src/main/resources/theme/keycloak/common/resources",
|
|
||||||
"author": {
|
|
||||||
"name": "Angular Core Team",
|
|
||||||
"email": "angular-core+npm@google.com"
|
|
||||||
},
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/angular/angular.js/issues"
|
|
||||||
},
|
|
||||||
"bundleDependencies": false,
|
|
||||||
"deprecated": false,
|
|
||||||
"description": "AngularJS module for interacting with RESTful server-side data sources",
|
|
||||||
"homepage": "http://angularjs.org",
|
|
||||||
"jspm": {
|
|
||||||
"shim": {
|
|
||||||
"angular-resource": {
|
|
||||||
"deps": [
|
|
||||||
"angular"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"angular",
|
|
||||||
"framework",
|
|
||||||
"browser",
|
|
||||||
"rest",
|
|
||||||
"client-side"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "index.js",
|
|
||||||
"name": "angular-resource",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/angular/angular.js.git"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"version": "1.8.0"
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2016 Angular
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
|
@ -1,68 +0,0 @@
|
||||||
# packaged angular-route
|
|
||||||
|
|
||||||
This repo is for distribution on `npm` and `bower`. The source for this module is in the
|
|
||||||
[main AngularJS repo](https://github.com/angular/angular.js/tree/master/src/ngRoute).
|
|
||||||
Please file issues and pull requests against that repo.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
You can install this package either with `npm` or with `bower`.
|
|
||||||
|
|
||||||
### npm
|
|
||||||
|
|
||||||
```shell
|
|
||||||
npm install angular-route
|
|
||||||
```
|
|
||||||
|
|
||||||
Then add `ngRoute` as a dependency for your app:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
angular.module('myApp', [require('angular-route')]);
|
|
||||||
```
|
|
||||||
|
|
||||||
### bower
|
|
||||||
|
|
||||||
```shell
|
|
||||||
bower install angular-route
|
|
||||||
```
|
|
||||||
|
|
||||||
Add a `<script>` to your `index.html`:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<script src="/bower_components/angular-route/angular-route.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
Then add `ngRoute` as a dependency for your app:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
angular.module('myApp', ['ngRoute']);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
Documentation is available on the
|
|
||||||
[AngularJS docs site](http://docs.angularjs.org/api/ngRoute).
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
The MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,17 +0,0 @@
|
||||||
/*
|
|
||||||
AngularJS v1.8.0
|
|
||||||
(c) 2010-2020 Google, Inc. http://angularjs.org
|
|
||||||
License: MIT
|
|
||||||
*/
|
|
||||||
(function(I,b){'use strict';function z(b,h){var d=[],c=b.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)(\*\?|[?*])?/g,function(b,c,h,k){b="?"===k||"*?"===k;k="*"===k||"*?"===k;d.push({name:h,optional:b});c=c||"";return(b?"(?:"+c:c+"(?:")+(k?"(.+?)":"([^/]+)")+(b?"?)?":")")}).replace(/([/$*])/g,"\\$1");h.ignoreTrailingSlashes&&(c=c.replace(/\/+$/,"")+"/*");return{keys:d,regexp:new RegExp("^"+c+"(?:[?#]|$)",h.caseInsensitiveMatch?"i":"")}}function A(b){p&&b.get("$route")}function v(u,h,d){return{restrict:"ECA",
|
|
||||||
terminal:!0,priority:400,transclude:"element",link:function(c,f,g,l,k){function q(){r&&(d.cancel(r),r=null);m&&(m.$destroy(),m=null);s&&(r=d.leave(s),r.done(function(b){!1!==b&&(r=null)}),s=null)}function C(){var g=u.current&&u.current.locals;if(b.isDefined(g&&g.$template)){var g=c.$new(),l=u.current;s=k(g,function(g){d.enter(g,null,s||f).done(function(d){!1===d||!b.isDefined(w)||w&&!c.$eval(w)||h()});q()});m=l.scope=g;m.$emit("$viewContentLoaded");m.$eval(p)}else q()}var m,s,r,w=g.autoscroll,p=g.onload||
|
|
||||||
"";c.$on("$routeChangeSuccess",C);C()}}}function x(b,h,d){return{restrict:"ECA",priority:-400,link:function(c,f){var g=d.current,l=g.locals;f.html(l.$template);var k=b(f.contents());if(g.controller){l.$scope=c;var q=h(g.controller,l);g.controllerAs&&(c[g.controllerAs]=q);f.data("$ngControllerController",q);f.children().data("$ngControllerController",q)}c[g.resolveAs||"$resolve"]=l;k(c)}}}var D,E,F,G,y=b.module("ngRoute",[]).info({angularVersion:"1.8.0"}).provider("$route",function(){function u(d,
|
|
||||||
c){return b.extend(Object.create(d),c)}D=b.isArray;E=b.isObject;F=b.isDefined;G=b.noop;var h={};this.when=function(d,c){var f;f=void 0;if(D(c)){f=f||[];for(var g=0,l=c.length;g<l;g++)f[g]=c[g]}else if(E(c))for(g in f=f||{},c)if("$"!==g.charAt(0)||"$"!==g.charAt(1))f[g]=c[g];f=f||c;b.isUndefined(f.reloadOnUrl)&&(f.reloadOnUrl=!0);b.isUndefined(f.reloadOnSearch)&&(f.reloadOnSearch=!0);b.isUndefined(f.caseInsensitiveMatch)&&(f.caseInsensitiveMatch=this.caseInsensitiveMatch);h[d]=b.extend(f,{originalPath:d},
|
|
||||||
d&&z(d,f));d&&(g="/"===d[d.length-1]?d.substr(0,d.length-1):d+"/",h[g]=b.extend({originalPath:d,redirectTo:d},z(g,f)));return this};this.caseInsensitiveMatch=!1;this.otherwise=function(b){"string"===typeof b&&(b={redirectTo:b});this.when(null,b);return this};p=!0;this.eagerInstantiationEnabled=function(b){return F(b)?(p=b,this):p};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$templateRequest","$sce","$browser",function(d,c,f,g,l,k,q,p){function m(a){var e=t.current;n=A();(x=
|
|
||||||
!B&&n&&e&&n.$$route===e.$$route&&(!n.reloadOnUrl||!n.reloadOnSearch&&b.equals(n.pathParams,e.pathParams)))||!e&&!n||d.$broadcast("$routeChangeStart",n,e).defaultPrevented&&a&&a.preventDefault()}function s(){var a=t.current,e=n;if(x)a.params=e.params,b.copy(a.params,f),d.$broadcast("$routeUpdate",a);else if(e||a){B=!1;t.current=e;var c=g.resolve(e);p.$$incOutstandingRequestCount("$route");c.then(r).then(w).then(function(g){return g&&c.then(y).then(function(c){e===t.current&&(e&&(e.locals=c,b.copy(e.params,
|
|
||||||
f)),d.$broadcast("$routeChangeSuccess",e,a))})}).catch(function(b){e===t.current&&d.$broadcast("$routeChangeError",e,a,b)}).finally(function(){p.$$completeOutstandingRequest(G,"$route")})}}function r(a){var e={route:a,hasRedirection:!1};if(a)if(a.redirectTo)if(b.isString(a.redirectTo))e.path=v(a.redirectTo,a.params),e.search=a.params,e.hasRedirection=!0;else{var d=c.path(),f=c.search();a=a.redirectTo(a.pathParams,d,f);b.isDefined(a)&&(e.url=a,e.hasRedirection=!0)}else if(a.resolveRedirectTo)return g.resolve(l.invoke(a.resolveRedirectTo)).then(function(a){b.isDefined(a)&&
|
|
||||||
(e.url=a,e.hasRedirection=!0);return e});return e}function w(a){var b=!0;if(a.route!==t.current)b=!1;else if(a.hasRedirection){var g=c.url(),d=a.url;d?c.url(d).replace():d=c.path(a.path).search(a.search).replace().url();d!==g&&(b=!1)}return b}function y(a){if(a){var e=b.extend({},a.resolve);b.forEach(e,function(a,c){e[c]=b.isString(a)?l.get(a):l.invoke(a,null,null,c)});a=z(a);b.isDefined(a)&&(e.$template=a);return g.all(e)}}function z(a){var e,c;b.isDefined(e=a.template)?b.isFunction(e)&&(e=e(a.params)):
|
|
||||||
b.isDefined(c=a.templateUrl)&&(b.isFunction(c)&&(c=c(a.params)),b.isDefined(c)&&(a.loadedTemplateUrl=q.valueOf(c),e=k(c)));return e}function A(){var a,e;b.forEach(h,function(d,g){var f;if(f=!e){var h=c.path();f=d.keys;var l={};if(d.regexp)if(h=d.regexp.exec(h)){for(var k=1,p=h.length;k<p;++k){var m=f[k-1],n=h[k];m&&n&&(l[m.name]=n)}f=l}else f=null;else f=null;f=a=f}f&&(e=u(d,{params:b.extend({},c.search(),a),pathParams:a}),e.$$route=d)});return e||h[null]&&u(h[null],{params:{},pathParams:{}})}function v(a,
|
|
||||||
c){var d=[];b.forEach((a||"").split(":"),function(a,b){if(0===b)d.push(a);else{var f=a.match(/(\w+)(?:[?*])?(.*)/),g=f[1];d.push(c[g]);d.push(f[2]||"");delete c[g]}});return d.join("")}var B=!1,n,x,t={routes:h,reload:function(){B=!0;var a={defaultPrevented:!1,preventDefault:function(){this.defaultPrevented=!0;B=!1}};d.$evalAsync(function(){m(a);a.defaultPrevented||s()})},updateParams:function(a){if(this.current&&this.current.$$route)a=b.extend({},this.current.params,a),c.path(v(this.current.$$route.originalPath,
|
|
||||||
a)),c.search(a);else throw H("norout");}};d.$on("$locationChangeStart",m);d.$on("$locationChangeSuccess",s);return t}]}).run(A),H=b.$$minErr("ngRoute"),p;A.$inject=["$injector"];y.provider("$routeParams",function(){this.$get=function(){return{}}});y.directive("ngView",v);y.directive("ngView",x);v.$inject=["$route","$anchorScroll","$animate"];x.$inject=["$compile","$controller","$route"]})(window,window.angular);
|
|
||||||
//# sourceMappingURL=angular-route.min.js.map
|
|
File diff suppressed because one or more lines are too long
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"name": "angular-route",
|
|
||||||
"version": "1.8.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "./angular-route.js",
|
|
||||||
"ignore": [],
|
|
||||||
"dependencies": {
|
|
||||||
"angular": "1.8.0"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
require('./angular-route');
|
|
||||||
module.exports = 'ngRoute';
|
|
|
@ -1,63 +0,0 @@
|
||||||
{
|
|
||||||
"_from": "angular-route@1.8.0",
|
|
||||||
"_id": "angular-route@1.8.0",
|
|
||||||
"_inBundle": false,
|
|
||||||
"_integrity": "sha512-ORvXAdVfCCA6XFwyjSkVQFFGufj0mNGiCvBR93Qsii8+7t/6Ioy6wheUoCj1x4NWUv7hAq3nYYGCVO6QEKb1BQ==",
|
|
||||||
"_location": "/angular-route",
|
|
||||||
"_phantomChildren": {},
|
|
||||||
"_requested": {
|
|
||||||
"type": "version",
|
|
||||||
"registry": true,
|
|
||||||
"raw": "angular-route@1.8.0",
|
|
||||||
"name": "angular-route",
|
|
||||||
"escapedName": "angular-route",
|
|
||||||
"rawSpec": "1.8.0",
|
|
||||||
"saveSpec": null,
|
|
||||||
"fetchSpec": "1.8.0"
|
|
||||||
},
|
|
||||||
"_requiredBy": [
|
|
||||||
"/"
|
|
||||||
],
|
|
||||||
"_resolved": "https://registry.npmjs.org/angular-route/-/angular-route-1.8.0.tgz",
|
|
||||||
"_shasum": "cb8066c5d34284ffd6a15ac7be1b3d51c5ad7bb2",
|
|
||||||
"_spec": "angular-route@1.8.0",
|
|
||||||
"_where": "/home/abstractj/github/keycloak/themes/src/main/resources/theme/keycloak/common/resources",
|
|
||||||
"author": {
|
|
||||||
"name": "Angular Core Team",
|
|
||||||
"email": "angular-core+npm@google.com"
|
|
||||||
},
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/angular/angular.js/issues"
|
|
||||||
},
|
|
||||||
"bundleDependencies": false,
|
|
||||||
"deprecated": false,
|
|
||||||
"description": "AngularJS router module",
|
|
||||||
"homepage": "http://angularjs.org",
|
|
||||||
"jspm": {
|
|
||||||
"shim": {
|
|
||||||
"angular-route": {
|
|
||||||
"deps": [
|
|
||||||
"angular"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"angular",
|
|
||||||
"framework",
|
|
||||||
"browser",
|
|
||||||
"router",
|
|
||||||
"client-side"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "index.js",
|
|
||||||
"name": "angular-route",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/angular/angular.js.git"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"version": "1.8.0"
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2016 Angular
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
|
@ -1,68 +0,0 @@
|
||||||
# packaged angular-sanitize
|
|
||||||
|
|
||||||
This repo is for distribution on `npm` and `bower`. The source for this module is in the
|
|
||||||
[main AngularJS repo](https://github.com/angular/angular.js/tree/master/src/ngSanitize).
|
|
||||||
Please file issues and pull requests against that repo.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
You can install this package either with `npm` or with `bower`.
|
|
||||||
|
|
||||||
### npm
|
|
||||||
|
|
||||||
```shell
|
|
||||||
npm install angular-sanitize
|
|
||||||
```
|
|
||||||
|
|
||||||
Then add `ngSanitize` as a dependency for your app:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
angular.module('myApp', [require('angular-sanitize')]);
|
|
||||||
```
|
|
||||||
|
|
||||||
### bower
|
|
||||||
|
|
||||||
```shell
|
|
||||||
bower install angular-sanitize
|
|
||||||
```
|
|
||||||
|
|
||||||
Add a `<script>` to your `index.html`:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<script src="/bower_components/angular-sanitize/angular-sanitize.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
Then add `ngSanitize` as a dependency for your app:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
angular.module('myApp', ['ngSanitize']);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
Documentation is available on the
|
|
||||||
[AngularJS docs site](http://docs.angularjs.org/api/ngSanitize).
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
The MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
|
@ -1,913 +0,0 @@
|
||||||
/**
|
|
||||||
* @license AngularJS v1.8.0
|
|
||||||
* (c) 2010-2020 Google, Inc. http://angularjs.org
|
|
||||||
* License: MIT
|
|
||||||
*/
|
|
||||||
(function(window, angular) {'use strict';
|
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
||||||
* Any commits to this file should be reviewed with security in mind. *
|
|
||||||
* Changes to this file can potentially create security vulnerabilities. *
|
|
||||||
* An approval from 2 Core members with history of modifying *
|
|
||||||
* this file is required. *
|
|
||||||
* *
|
|
||||||
* Does the change somehow allow for arbitrary javascript to be executed? *
|
|
||||||
* Or allows for someone to change the prototype of built-in objects? *
|
|
||||||
* Or gives undesired access to variables likes document or window? *
|
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
||||||
|
|
||||||
var $sanitizeMinErr = angular.$$minErr('$sanitize');
|
|
||||||
var bind;
|
|
||||||
var extend;
|
|
||||||
var forEach;
|
|
||||||
var isArray;
|
|
||||||
var isDefined;
|
|
||||||
var lowercase;
|
|
||||||
var noop;
|
|
||||||
var nodeContains;
|
|
||||||
var htmlParser;
|
|
||||||
var htmlSanitizeWriter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc module
|
|
||||||
* @name ngSanitize
|
|
||||||
* @description
|
|
||||||
*
|
|
||||||
* The `ngSanitize` module provides functionality to sanitize HTML.
|
|
||||||
*
|
|
||||||
* See {@link ngSanitize.$sanitize `$sanitize`} for usage.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc service
|
|
||||||
* @name $sanitize
|
|
||||||
* @kind function
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Sanitizes an html string by stripping all potentially dangerous tokens.
|
|
||||||
*
|
|
||||||
* The input is sanitized by parsing the HTML into tokens. All safe tokens (from a whitelist) are
|
|
||||||
* then serialized back to a properly escaped HTML string. This means that no unsafe input can make
|
|
||||||
* it into the returned string.
|
|
||||||
*
|
|
||||||
* The whitelist for URL sanitization of attribute values is configured using the functions
|
|
||||||
* `aHrefSanitizationWhitelist` and `imgSrcSanitizationWhitelist` of {@link $compileProvider}.
|
|
||||||
*
|
|
||||||
* The input may also contain SVG markup if this is enabled via {@link $sanitizeProvider}.
|
|
||||||
*
|
|
||||||
* @param {string} html HTML input.
|
|
||||||
* @returns {string} Sanitized HTML.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
<example module="sanitizeExample" deps="angular-sanitize.js" name="sanitize-service">
|
|
||||||
<file name="index.html">
|
|
||||||
<script>
|
|
||||||
angular.module('sanitizeExample', ['ngSanitize'])
|
|
||||||
.controller('ExampleController', ['$scope', '$sce', function($scope, $sce) {
|
|
||||||
$scope.snippet =
|
|
||||||
'<p style="color:blue">an html\n' +
|
|
||||||
'<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
|
|
||||||
'snippet</p>';
|
|
||||||
$scope.deliberatelyTrustDangerousSnippet = function() {
|
|
||||||
return $sce.trustAsHtml($scope.snippet);
|
|
||||||
};
|
|
||||||
}]);
|
|
||||||
</script>
|
|
||||||
<div ng-controller="ExampleController">
|
|
||||||
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>Directive</td>
|
|
||||||
<td>How</td>
|
|
||||||
<td>Source</td>
|
|
||||||
<td>Rendered</td>
|
|
||||||
</tr>
|
|
||||||
<tr id="bind-html-with-sanitize">
|
|
||||||
<td>ng-bind-html</td>
|
|
||||||
<td>Automatically uses $sanitize</td>
|
|
||||||
<td><pre><div ng-bind-html="snippet"><br/></div></pre></td>
|
|
||||||
<td><div ng-bind-html="snippet"></div></td>
|
|
||||||
</tr>
|
|
||||||
<tr id="bind-html-with-trust">
|
|
||||||
<td>ng-bind-html</td>
|
|
||||||
<td>Bypass $sanitize by explicitly trusting the dangerous value</td>
|
|
||||||
<td>
|
|
||||||
<pre><div ng-bind-html="deliberatelyTrustDangerousSnippet()">
|
|
||||||
</div></pre>
|
|
||||||
</td>
|
|
||||||
<td><div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div></td>
|
|
||||||
</tr>
|
|
||||||
<tr id="bind-default">
|
|
||||||
<td>ng-bind</td>
|
|
||||||
<td>Automatically escapes</td>
|
|
||||||
<td><pre><div ng-bind="snippet"><br/></div></pre></td>
|
|
||||||
<td><div ng-bind="snippet"></div></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</file>
|
|
||||||
<file name="protractor.js" type="protractor">
|
|
||||||
it('should sanitize the html snippet by default', function() {
|
|
||||||
expect(element(by.css('#bind-html-with-sanitize div')).getAttribute('innerHTML')).
|
|
||||||
toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should inline raw snippet if bound to a trusted value', function() {
|
|
||||||
expect(element(by.css('#bind-html-with-trust div')).getAttribute('innerHTML')).
|
|
||||||
toBe("<p style=\"color:blue\">an html\n" +
|
|
||||||
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
|
|
||||||
"snippet</p>");
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should escape snippet without any filter', function() {
|
|
||||||
expect(element(by.css('#bind-default div')).getAttribute('innerHTML')).
|
|
||||||
toBe("<p style=\"color:blue\">an html\n" +
|
|
||||||
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
|
|
||||||
"snippet</p>");
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update', function() {
|
|
||||||
element(by.model('snippet')).clear();
|
|
||||||
element(by.model('snippet')).sendKeys('new <b onclick="alert(1)">text</b>');
|
|
||||||
expect(element(by.css('#bind-html-with-sanitize div')).getAttribute('innerHTML')).
|
|
||||||
toBe('new <b>text</b>');
|
|
||||||
expect(element(by.css('#bind-html-with-trust div')).getAttribute('innerHTML')).toBe(
|
|
||||||
'new <b onclick="alert(1)">text</b>');
|
|
||||||
expect(element(by.css('#bind-default div')).getAttribute('innerHTML')).toBe(
|
|
||||||
"new <b onclick=\"alert(1)\">text</b>");
|
|
||||||
});
|
|
||||||
</file>
|
|
||||||
</example>
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc provider
|
|
||||||
* @name $sanitizeProvider
|
|
||||||
* @this
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Creates and configures {@link $sanitize} instance.
|
|
||||||
*/
|
|
||||||
function $SanitizeProvider() {
|
|
||||||
var hasBeenInstantiated = false;
|
|
||||||
var svgEnabled = false;
|
|
||||||
|
|
||||||
this.$get = ['$$sanitizeUri', function($$sanitizeUri) {
|
|
||||||
hasBeenInstantiated = true;
|
|
||||||
if (svgEnabled) {
|
|
||||||
extend(validElements, svgElements);
|
|
||||||
}
|
|
||||||
return function(html) {
|
|
||||||
var buf = [];
|
|
||||||
htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) {
|
|
||||||
return !/^unsafe:/.test($$sanitizeUri(uri, isImage));
|
|
||||||
}));
|
|
||||||
return buf.join('');
|
|
||||||
};
|
|
||||||
}];
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name $sanitizeProvider#enableSvg
|
|
||||||
* @kind function
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Enables a subset of svg to be supported by the sanitizer.
|
|
||||||
*
|
|
||||||
* <div class="alert alert-warning">
|
|
||||||
* <p>By enabling this setting without taking other precautions, you might expose your
|
|
||||||
* application to click-hijacking attacks. In these attacks, sanitized svg elements could be positioned
|
|
||||||
* outside of the containing element and be rendered over other elements on the page (e.g. a login
|
|
||||||
* link). Such behavior can then result in phishing incidents.</p>
|
|
||||||
*
|
|
||||||
* <p>To protect against these, explicitly setup `overflow: hidden` css rule for all potential svg
|
|
||||||
* tags within the sanitized content:</p>
|
|
||||||
*
|
|
||||||
* <br>
|
|
||||||
*
|
|
||||||
* <pre><code>
|
|
||||||
* .rootOfTheIncludedContent svg {
|
|
||||||
* overflow: hidden !important;
|
|
||||||
* }
|
|
||||||
* </code></pre>
|
|
||||||
* </div>
|
|
||||||
*
|
|
||||||
* @param {boolean=} flag Enable or disable SVG support in the sanitizer.
|
|
||||||
* @returns {boolean|$sanitizeProvider} Returns the currently configured value if called
|
|
||||||
* without an argument or self for chaining otherwise.
|
|
||||||
*/
|
|
||||||
this.enableSvg = function(enableSvg) {
|
|
||||||
if (isDefined(enableSvg)) {
|
|
||||||
svgEnabled = enableSvg;
|
|
||||||
return this;
|
|
||||||
} else {
|
|
||||||
return svgEnabled;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name $sanitizeProvider#addValidElements
|
|
||||||
* @kind function
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Extends the built-in lists of valid HTML/SVG elements, i.e. elements that are considered safe
|
|
||||||
* and are not stripped off during sanitization. You can extend the following lists of elements:
|
|
||||||
*
|
|
||||||
* - `htmlElements`: A list of elements (tag names) to extend the current list of safe HTML
|
|
||||||
* elements. HTML elements considered safe will not be removed during sanitization. All other
|
|
||||||
* elements will be stripped off.
|
|
||||||
*
|
|
||||||
* - `htmlVoidElements`: This is similar to `htmlElements`, but marks the elements as
|
|
||||||
* "void elements" (similar to HTML
|
|
||||||
* [void elements](https://rawgit.com/w3c/html/html5.1-2/single-page.html#void-elements)). These
|
|
||||||
* elements have no end tag and cannot have content.
|
|
||||||
*
|
|
||||||
* - `svgElements`: This is similar to `htmlElements`, but for SVG elements. This list is only
|
|
||||||
* taken into account if SVG is {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for
|
|
||||||
* `$sanitize`.
|
|
||||||
*
|
|
||||||
* <div class="alert alert-info">
|
|
||||||
* This method must be called during the {@link angular.Module#config config} phase. Once the
|
|
||||||
* `$sanitize` service has been instantiated, this method has no effect.
|
|
||||||
* </div>
|
|
||||||
*
|
|
||||||
* <div class="alert alert-warning">
|
|
||||||
* Keep in mind that extending the built-in lists of elements may expose your app to XSS or
|
|
||||||
* other vulnerabilities. Be very mindful of the elements you add.
|
|
||||||
* </div>
|
|
||||||
*
|
|
||||||
* @param {Array<String>|Object} elements - A list of valid HTML elements or an object with one or
|
|
||||||
* more of the following properties:
|
|
||||||
* - **htmlElements** - `{Array<String>}` - A list of elements to extend the current list of
|
|
||||||
* HTML elements.
|
|
||||||
* - **htmlVoidElements** - `{Array<String>}` - A list of elements to extend the current list of
|
|
||||||
* void HTML elements; i.e. elements that do not have an end tag.
|
|
||||||
* - **svgElements** - `{Array<String>}` - A list of elements to extend the current list of SVG
|
|
||||||
* elements. The list of SVG elements is only taken into account if SVG is
|
|
||||||
* {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for `$sanitize`.
|
|
||||||
*
|
|
||||||
* Passing an array (`[...]`) is equivalent to passing `{htmlElements: [...]}`.
|
|
||||||
*
|
|
||||||
* @return {$sanitizeProvider} Returns self for chaining.
|
|
||||||
*/
|
|
||||||
this.addValidElements = function(elements) {
|
|
||||||
if (!hasBeenInstantiated) {
|
|
||||||
if (isArray(elements)) {
|
|
||||||
elements = {htmlElements: elements};
|
|
||||||
}
|
|
||||||
|
|
||||||
addElementsTo(svgElements, elements.svgElements);
|
|
||||||
addElementsTo(voidElements, elements.htmlVoidElements);
|
|
||||||
addElementsTo(validElements, elements.htmlVoidElements);
|
|
||||||
addElementsTo(validElements, elements.htmlElements);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name $sanitizeProvider#addValidAttrs
|
|
||||||
* @kind function
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Extends the built-in list of valid attributes, i.e. attributes that are considered safe and are
|
|
||||||
* not stripped off during sanitization.
|
|
||||||
*
|
|
||||||
* **Note**:
|
|
||||||
* The new attributes will not be treated as URI attributes, which means their values will not be
|
|
||||||
* sanitized as URIs using `$compileProvider`'s
|
|
||||||
* {@link ng.$compileProvider#aHrefSanitizationWhitelist aHrefSanitizationWhitelist} and
|
|
||||||
* {@link ng.$compileProvider#imgSrcSanitizationWhitelist imgSrcSanitizationWhitelist}.
|
|
||||||
*
|
|
||||||
* <div class="alert alert-info">
|
|
||||||
* This method must be called during the {@link angular.Module#config config} phase. Once the
|
|
||||||
* `$sanitize` service has been instantiated, this method has no effect.
|
|
||||||
* </div>
|
|
||||||
*
|
|
||||||
* <div class="alert alert-warning">
|
|
||||||
* Keep in mind that extending the built-in list of attributes may expose your app to XSS or
|
|
||||||
* other vulnerabilities. Be very mindful of the attributes you add.
|
|
||||||
* </div>
|
|
||||||
*
|
|
||||||
* @param {Array<String>} attrs - A list of valid attributes.
|
|
||||||
*
|
|
||||||
* @returns {$sanitizeProvider} Returns self for chaining.
|
|
||||||
*/
|
|
||||||
this.addValidAttrs = function(attrs) {
|
|
||||||
if (!hasBeenInstantiated) {
|
|
||||||
extend(validAttrs, arrayToMap(attrs, true));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private stuff
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bind = angular.bind;
|
|
||||||
extend = angular.extend;
|
|
||||||
forEach = angular.forEach;
|
|
||||||
isArray = angular.isArray;
|
|
||||||
isDefined = angular.isDefined;
|
|
||||||
lowercase = angular.$$lowercase;
|
|
||||||
noop = angular.noop;
|
|
||||||
|
|
||||||
htmlParser = htmlParserImpl;
|
|
||||||
htmlSanitizeWriter = htmlSanitizeWriterImpl;
|
|
||||||
|
|
||||||
nodeContains = window.Node.prototype.contains || /** @this */ function(arg) {
|
|
||||||
// eslint-disable-next-line no-bitwise
|
|
||||||
return !!(this.compareDocumentPosition(arg) & 16);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Regular Expressions for parsing tags and attributes
|
|
||||||
var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
|
|
||||||
// Match everything outside of normal chars and " (quote character)
|
|
||||||
NON_ALPHANUMERIC_REGEXP = /([^#-~ |!])/g;
|
|
||||||
|
|
||||||
|
|
||||||
// Good source of info about elements and attributes
|
|
||||||
// http://dev.w3.org/html5/spec/Overview.html#semantics
|
|
||||||
// http://simon.html5.org/html-elements
|
|
||||||
|
|
||||||
// Safe Void Elements - HTML5
|
|
||||||
// http://dev.w3.org/html5/spec/Overview.html#void-elements
|
|
||||||
var voidElements = stringToMap('area,br,col,hr,img,wbr');
|
|
||||||
|
|
||||||
// Elements that you can, intentionally, leave open (and which close themselves)
|
|
||||||
// http://dev.w3.org/html5/spec/Overview.html#optional-tags
|
|
||||||
var optionalEndTagBlockElements = stringToMap('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr'),
|
|
||||||
optionalEndTagInlineElements = stringToMap('rp,rt'),
|
|
||||||
optionalEndTagElements = extend({},
|
|
||||||
optionalEndTagInlineElements,
|
|
||||||
optionalEndTagBlockElements);
|
|
||||||
|
|
||||||
// Safe Block Elements - HTML5
|
|
||||||
var blockElements = extend({}, optionalEndTagBlockElements, stringToMap('address,article,' +
|
|
||||||
'aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,' +
|
|
||||||
'h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul'));
|
|
||||||
|
|
||||||
// Inline Elements - HTML5
|
|
||||||
var inlineElements = extend({}, optionalEndTagInlineElements, stringToMap('a,abbr,acronym,b,' +
|
|
||||||
'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,' +
|
|
||||||
'samp,small,span,strike,strong,sub,sup,time,tt,u,var'));
|
|
||||||
|
|
||||||
// SVG Elements
|
|
||||||
// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements
|
|
||||||
// Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted.
|
|
||||||
// They can potentially allow for arbitrary javascript to be executed. See #11290
|
|
||||||
var svgElements = stringToMap('circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,' +
|
|
||||||
'hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,' +
|
|
||||||
'radialGradient,rect,stop,svg,switch,text,title,tspan');
|
|
||||||
|
|
||||||
// Blocked Elements (will be stripped)
|
|
||||||
var blockedElements = stringToMap('script,style');
|
|
||||||
|
|
||||||
var validElements = extend({},
|
|
||||||
voidElements,
|
|
||||||
blockElements,
|
|
||||||
inlineElements,
|
|
||||||
optionalEndTagElements);
|
|
||||||
|
|
||||||
//Attributes that have href and hence need to be sanitized
|
|
||||||
var uriAttrs = stringToMap('background,cite,href,longdesc,src,xlink:href,xml:base');
|
|
||||||
|
|
||||||
var htmlAttrs = stringToMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' +
|
|
||||||
'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' +
|
|
||||||
'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' +
|
|
||||||
'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' +
|
|
||||||
'valign,value,vspace,width');
|
|
||||||
|
|
||||||
// SVG attributes (without "id" and "name" attributes)
|
|
||||||
// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes
|
|
||||||
var svgAttrs = stringToMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' +
|
|
||||||
'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,' +
|
|
||||||
'cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,' +
|
|
||||||
'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,' +
|
|
||||||
'height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,' +
|
|
||||||
'marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,' +
|
|
||||||
'max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,' +
|
|
||||||
'path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,' +
|
|
||||||
'requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,' +
|
|
||||||
'stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,' +
|
|
||||||
'stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,' +
|
|
||||||
'stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,' +
|
|
||||||
'underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,' +
|
|
||||||
'width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,' +
|
|
||||||
'xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan', true);
|
|
||||||
|
|
||||||
var validAttrs = extend({},
|
|
||||||
uriAttrs,
|
|
||||||
svgAttrs,
|
|
||||||
htmlAttrs);
|
|
||||||
|
|
||||||
function stringToMap(str, lowercaseKeys) {
|
|
||||||
return arrayToMap(str.split(','), lowercaseKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
function arrayToMap(items, lowercaseKeys) {
|
|
||||||
var obj = {}, i;
|
|
||||||
for (i = 0; i < items.length; i++) {
|
|
||||||
obj[lowercaseKeys ? lowercase(items[i]) : items[i]] = true;
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
function addElementsTo(elementsMap, newElements) {
|
|
||||||
if (newElements && newElements.length) {
|
|
||||||
extend(elementsMap, arrayToMap(newElements));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an inert document that contains the dirty HTML that needs sanitizing
|
|
||||||
* Depending upon browser support we use one of three strategies for doing this.
|
|
||||||
* Support: Safari 10.x -> XHR strategy
|
|
||||||
* Support: Firefox -> DomParser strategy
|
|
||||||
*/
|
|
||||||
var getInertBodyElement /* function(html: string): HTMLBodyElement */ = (function(window, document) {
|
|
||||||
var inertDocument;
|
|
||||||
if (document && document.implementation) {
|
|
||||||
inertDocument = document.implementation.createHTMLDocument('inert');
|
|
||||||
} else {
|
|
||||||
throw $sanitizeMinErr('noinert', 'Can\'t create an inert html document');
|
|
||||||
}
|
|
||||||
var inertBodyElement = (inertDocument.documentElement || inertDocument.getDocumentElement()).querySelector('body');
|
|
||||||
|
|
||||||
// Check for the Safari 10.1 bug - which allows JS to run inside the SVG G element
|
|
||||||
inertBodyElement.innerHTML = '<svg><g onload="this.parentNode.remove()"></g></svg>';
|
|
||||||
if (!inertBodyElement.querySelector('svg')) {
|
|
||||||
return getInertBodyElement_XHR;
|
|
||||||
} else {
|
|
||||||
// Check for the Firefox bug - which prevents the inner img JS from being sanitized
|
|
||||||
inertBodyElement.innerHTML = '<svg><p><style><img src="</style><img src=x onerror=alert(1)//">';
|
|
||||||
if (inertBodyElement.querySelector('svg img')) {
|
|
||||||
return getInertBodyElement_DOMParser;
|
|
||||||
} else {
|
|
||||||
return getInertBodyElement_InertDocument;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getInertBodyElement_XHR(html) {
|
|
||||||
// We add this dummy element to ensure that the rest of the content is parsed as expected
|
|
||||||
// e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the `<head>` tag.
|
|
||||||
html = '<remove></remove>' + html;
|
|
||||||
try {
|
|
||||||
html = encodeURI(html);
|
|
||||||
} catch (e) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
var xhr = new window.XMLHttpRequest();
|
|
||||||
xhr.responseType = 'document';
|
|
||||||
xhr.open('GET', 'data:text/html;charset=utf-8,' + html, false);
|
|
||||||
xhr.send(null);
|
|
||||||
var body = xhr.response.body;
|
|
||||||
body.firstChild.remove();
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getInertBodyElement_DOMParser(html) {
|
|
||||||
// We add this dummy element to ensure that the rest of the content is parsed as expected
|
|
||||||
// e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the `<head>` tag.
|
|
||||||
html = '<remove></remove>' + html;
|
|
||||||
try {
|
|
||||||
var body = new window.DOMParser().parseFromString(html, 'text/html').body;
|
|
||||||
body.firstChild.remove();
|
|
||||||
return body;
|
|
||||||
} catch (e) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getInertBodyElement_InertDocument(html) {
|
|
||||||
inertBodyElement.innerHTML = html;
|
|
||||||
|
|
||||||
// Support: IE 9-11 only
|
|
||||||
// strip custom-namespaced attributes on IE<=11
|
|
||||||
if (document.documentMode) {
|
|
||||||
stripCustomNsAttrs(inertBodyElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
return inertBodyElement;
|
|
||||||
}
|
|
||||||
})(window, window.document);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @example
|
|
||||||
* htmlParser(htmlString, {
|
|
||||||
* start: function(tag, attrs) {},
|
|
||||||
* end: function(tag) {},
|
|
||||||
* chars: function(text) {},
|
|
||||||
* comment: function(text) {}
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* @param {string} html string
|
|
||||||
* @param {object} handler
|
|
||||||
*/
|
|
||||||
function htmlParserImpl(html, handler) {
|
|
||||||
if (html === null || html === undefined) {
|
|
||||||
html = '';
|
|
||||||
} else if (typeof html !== 'string') {
|
|
||||||
html = '' + html;
|
|
||||||
}
|
|
||||||
|
|
||||||
var inertBodyElement = getInertBodyElement(html);
|
|
||||||
if (!inertBodyElement) return '';
|
|
||||||
|
|
||||||
//mXSS protection
|
|
||||||
var mXSSAttempts = 5;
|
|
||||||
do {
|
|
||||||
if (mXSSAttempts === 0) {
|
|
||||||
throw $sanitizeMinErr('uinput', 'Failed to sanitize html because the input is unstable');
|
|
||||||
}
|
|
||||||
mXSSAttempts--;
|
|
||||||
|
|
||||||
// trigger mXSS if it is going to happen by reading and writing the innerHTML
|
|
||||||
html = inertBodyElement.innerHTML;
|
|
||||||
inertBodyElement = getInertBodyElement(html);
|
|
||||||
} while (html !== inertBodyElement.innerHTML);
|
|
||||||
|
|
||||||
var node = inertBodyElement.firstChild;
|
|
||||||
while (node) {
|
|
||||||
switch (node.nodeType) {
|
|
||||||
case 1: // ELEMENT_NODE
|
|
||||||
handler.start(node.nodeName.toLowerCase(), attrToMap(node.attributes));
|
|
||||||
break;
|
|
||||||
case 3: // TEXT NODE
|
|
||||||
handler.chars(node.textContent);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
var nextNode;
|
|
||||||
if (!(nextNode = node.firstChild)) {
|
|
||||||
if (node.nodeType === 1) {
|
|
||||||
handler.end(node.nodeName.toLowerCase());
|
|
||||||
}
|
|
||||||
nextNode = getNonDescendant('nextSibling', node);
|
|
||||||
if (!nextNode) {
|
|
||||||
while (nextNode == null) {
|
|
||||||
node = getNonDescendant('parentNode', node);
|
|
||||||
if (node === inertBodyElement) break;
|
|
||||||
nextNode = getNonDescendant('nextSibling', node);
|
|
||||||
if (node.nodeType === 1) {
|
|
||||||
handler.end(node.nodeName.toLowerCase());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node = nextNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((node = inertBodyElement.firstChild)) {
|
|
||||||
inertBodyElement.removeChild(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function attrToMap(attrs) {
|
|
||||||
var map = {};
|
|
||||||
for (var i = 0, ii = attrs.length; i < ii; i++) {
|
|
||||||
var attr = attrs[i];
|
|
||||||
map[attr.name] = attr.value;
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Escapes all potentially dangerous characters, so that the
|
|
||||||
* resulting string can be safely inserted into attribute or
|
|
||||||
* element text.
|
|
||||||
* @param value
|
|
||||||
* @returns {string} escaped text
|
|
||||||
*/
|
|
||||||
function encodeEntities(value) {
|
|
||||||
return value.
|
|
||||||
replace(/&/g, '&').
|
|
||||||
replace(SURROGATE_PAIR_REGEXP, function(value) {
|
|
||||||
var hi = value.charCodeAt(0);
|
|
||||||
var low = value.charCodeAt(1);
|
|
||||||
return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
|
|
||||||
}).
|
|
||||||
replace(NON_ALPHANUMERIC_REGEXP, function(value) {
|
|
||||||
return '&#' + value.charCodeAt(0) + ';';
|
|
||||||
}).
|
|
||||||
replace(/</g, '<').
|
|
||||||
replace(/>/g, '>');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create an HTML/XML writer which writes to buffer
|
|
||||||
* @param {Array} buf use buf.join('') to get out sanitized html string
|
|
||||||
* @returns {object} in the form of {
|
|
||||||
* start: function(tag, attrs) {},
|
|
||||||
* end: function(tag) {},
|
|
||||||
* chars: function(text) {},
|
|
||||||
* comment: function(text) {}
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
function htmlSanitizeWriterImpl(buf, uriValidator) {
|
|
||||||
var ignoreCurrentElement = false;
|
|
||||||
var out = bind(buf, buf.push);
|
|
||||||
return {
|
|
||||||
start: function(tag, attrs) {
|
|
||||||
tag = lowercase(tag);
|
|
||||||
if (!ignoreCurrentElement && blockedElements[tag]) {
|
|
||||||
ignoreCurrentElement = tag;
|
|
||||||
}
|
|
||||||
if (!ignoreCurrentElement && validElements[tag] === true) {
|
|
||||||
out('<');
|
|
||||||
out(tag);
|
|
||||||
forEach(attrs, function(value, key) {
|
|
||||||
var lkey = lowercase(key);
|
|
||||||
var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background');
|
|
||||||
if (validAttrs[lkey] === true &&
|
|
||||||
(uriAttrs[lkey] !== true || uriValidator(value, isImage))) {
|
|
||||||
out(' ');
|
|
||||||
out(key);
|
|
||||||
out('="');
|
|
||||||
out(encodeEntities(value));
|
|
||||||
out('"');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
out('>');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
end: function(tag) {
|
|
||||||
tag = lowercase(tag);
|
|
||||||
if (!ignoreCurrentElement && validElements[tag] === true && voidElements[tag] !== true) {
|
|
||||||
out('</');
|
|
||||||
out(tag);
|
|
||||||
out('>');
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line eqeqeq
|
|
||||||
if (tag == ignoreCurrentElement) {
|
|
||||||
ignoreCurrentElement = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
chars: function(chars) {
|
|
||||||
if (!ignoreCurrentElement) {
|
|
||||||
out(encodeEntities(chars));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When IE9-11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1' attribute to declare
|
|
||||||
* ns1 namespace and prefixes the attribute with 'ns1' (e.g. 'ns1:xlink:foo'). This is undesirable since we don't want
|
|
||||||
* to allow any of these custom attributes. This method strips them all.
|
|
||||||
*
|
|
||||||
* @param node Root element to process
|
|
||||||
*/
|
|
||||||
function stripCustomNsAttrs(node) {
|
|
||||||
while (node) {
|
|
||||||
if (node.nodeType === window.Node.ELEMENT_NODE) {
|
|
||||||
var attrs = node.attributes;
|
|
||||||
for (var i = 0, l = attrs.length; i < l; i++) {
|
|
||||||
var attrNode = attrs[i];
|
|
||||||
var attrName = attrNode.name.toLowerCase();
|
|
||||||
if (attrName === 'xmlns:ns1' || attrName.lastIndexOf('ns1:', 0) === 0) {
|
|
||||||
node.removeAttributeNode(attrNode);
|
|
||||||
i--;
|
|
||||||
l--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var nextNode = node.firstChild;
|
|
||||||
if (nextNode) {
|
|
||||||
stripCustomNsAttrs(nextNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
node = getNonDescendant('nextSibling', node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNonDescendant(propName, node) {
|
|
||||||
// An element is clobbered if its `propName` property points to one of its descendants
|
|
||||||
var nextNode = node[propName];
|
|
||||||
if (nextNode && nodeContains.call(node, nextNode)) {
|
|
||||||
throw $sanitizeMinErr('elclob', 'Failed to sanitize html because the element is clobbered: {0}', node.outerHTML || node.outerText);
|
|
||||||
}
|
|
||||||
return nextNode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function sanitizeText(chars) {
|
|
||||||
var buf = [];
|
|
||||||
var writer = htmlSanitizeWriter(buf, noop);
|
|
||||||
writer.chars(chars);
|
|
||||||
return buf.join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// define ngSanitize module and register $sanitize service
|
|
||||||
angular.module('ngSanitize', [])
|
|
||||||
.provider('$sanitize', $SanitizeProvider)
|
|
||||||
.info({ angularVersion: '1.8.0' });
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc filter
|
|
||||||
* @name linky
|
|
||||||
* @kind function
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Finds links in text input and turns them into html links. Supports `http/https/ftp/sftp/mailto` and
|
|
||||||
* plain email address links.
|
|
||||||
*
|
|
||||||
* Requires the {@link ngSanitize `ngSanitize`} module to be installed.
|
|
||||||
*
|
|
||||||
* @param {string} text Input text.
|
|
||||||
* @param {string} [target] Window (`_blank|_self|_parent|_top`) or named frame to open links in.
|
|
||||||
* @param {object|function(url)} [attributes] Add custom attributes to the link element.
|
|
||||||
*
|
|
||||||
* Can be one of:
|
|
||||||
*
|
|
||||||
* - `object`: A map of attributes
|
|
||||||
* - `function`: Takes the url as a parameter and returns a map of attributes
|
|
||||||
*
|
|
||||||
* If the map of attributes contains a value for `target`, it overrides the value of
|
|
||||||
* the target parameter.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @returns {string} Html-linkified and {@link $sanitize sanitized} text.
|
|
||||||
*
|
|
||||||
* @usage
|
|
||||||
<span ng-bind-html="linky_expression | linky"></span>
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
<example module="linkyExample" deps="angular-sanitize.js" name="linky-filter">
|
|
||||||
<file name="index.html">
|
|
||||||
<div ng-controller="ExampleController">
|
|
||||||
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>Filter</th>
|
|
||||||
<th>Source</th>
|
|
||||||
<th>Rendered</th>
|
|
||||||
</tr>
|
|
||||||
<tr id="linky-filter">
|
|
||||||
<td>linky filter</td>
|
|
||||||
<td>
|
|
||||||
<pre><div ng-bind-html="snippet | linky"><br></div></pre>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div ng-bind-html="snippet | linky"></div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr id="linky-target">
|
|
||||||
<td>linky target</td>
|
|
||||||
<td>
|
|
||||||
<pre><div ng-bind-html="snippetWithSingleURL | linky:'_blank'"><br></div></pre>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div ng-bind-html="snippetWithSingleURL | linky:'_blank'"></div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr id="linky-custom-attributes">
|
|
||||||
<td>linky custom attributes</td>
|
|
||||||
<td>
|
|
||||||
<pre><div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}"><br></div></pre>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}"></div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr id="escaped-html">
|
|
||||||
<td>no filter</td>
|
|
||||||
<td><pre><div ng-bind="snippet"><br></div></pre></td>
|
|
||||||
<td><div ng-bind="snippet"></div></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</file>
|
|
||||||
<file name="script.js">
|
|
||||||
angular.module('linkyExample', ['ngSanitize'])
|
|
||||||
.controller('ExampleController', ['$scope', function($scope) {
|
|
||||||
$scope.snippet =
|
|
||||||
'Pretty text with some links:\n' +
|
|
||||||
'http://angularjs.org/,\n' +
|
|
||||||
'mailto:us@somewhere.org,\n' +
|
|
||||||
'another@somewhere.org,\n' +
|
|
||||||
'and one more: ftp://127.0.0.1/.';
|
|
||||||
$scope.snippetWithSingleURL = 'http://angularjs.org/';
|
|
||||||
}]);
|
|
||||||
</file>
|
|
||||||
<file name="protractor.js" type="protractor">
|
|
||||||
it('should linkify the snippet with urls', function() {
|
|
||||||
expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
|
|
||||||
toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' +
|
|
||||||
'another@somewhere.org, and one more: ftp://127.0.0.1/.');
|
|
||||||
expect(element.all(by.css('#linky-filter a')).count()).toEqual(4);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not linkify snippet without the linky filter', function() {
|
|
||||||
expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()).
|
|
||||||
toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' +
|
|
||||||
'another@somewhere.org, and one more: ftp://127.0.0.1/.');
|
|
||||||
expect(element.all(by.css('#escaped-html a')).count()).toEqual(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update', function() {
|
|
||||||
element(by.model('snippet')).clear();
|
|
||||||
element(by.model('snippet')).sendKeys('new http://link.');
|
|
||||||
expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
|
|
||||||
toBe('new http://link.');
|
|
||||||
expect(element.all(by.css('#linky-filter a')).count()).toEqual(1);
|
|
||||||
expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText())
|
|
||||||
.toBe('new http://link.');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work with the target property', function() {
|
|
||||||
expect(element(by.id('linky-target')).
|
|
||||||
element(by.binding("snippetWithSingleURL | linky:'_blank'")).getText()).
|
|
||||||
toBe('http://angularjs.org/');
|
|
||||||
expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should optionally add custom attributes', function() {
|
|
||||||
expect(element(by.id('linky-custom-attributes')).
|
|
||||||
element(by.binding("snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}")).getText()).
|
|
||||||
toBe('http://angularjs.org/');
|
|
||||||
expect(element(by.css('#linky-custom-attributes a')).getAttribute('rel')).toEqual('nofollow');
|
|
||||||
});
|
|
||||||
</file>
|
|
||||||
</example>
|
|
||||||
*/
|
|
||||||
angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
|
|
||||||
var LINKY_URL_REGEXP =
|
|
||||||
/((s?ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,
|
|
||||||
MAILTO_REGEXP = /^mailto:/i;
|
|
||||||
|
|
||||||
var linkyMinErr = angular.$$minErr('linky');
|
|
||||||
var isDefined = angular.isDefined;
|
|
||||||
var isFunction = angular.isFunction;
|
|
||||||
var isObject = angular.isObject;
|
|
||||||
var isString = angular.isString;
|
|
||||||
|
|
||||||
return function(text, target, attributes) {
|
|
||||||
if (text == null || text === '') return text;
|
|
||||||
if (!isString(text)) throw linkyMinErr('notstring', 'Expected string but received: {0}', text);
|
|
||||||
|
|
||||||
var attributesFn =
|
|
||||||
isFunction(attributes) ? attributes :
|
|
||||||
isObject(attributes) ? function getAttributesObject() {return attributes;} :
|
|
||||||
function getEmptyAttributesObject() {return {};};
|
|
||||||
|
|
||||||
var match;
|
|
||||||
var raw = text;
|
|
||||||
var html = [];
|
|
||||||
var url;
|
|
||||||
var i;
|
|
||||||
while ((match = raw.match(LINKY_URL_REGEXP))) {
|
|
||||||
// We can not end in these as they are sometimes found at the end of the sentence
|
|
||||||
url = match[0];
|
|
||||||
// if we did not match ftp/http/www/mailto then assume mailto
|
|
||||||
if (!match[2] && !match[4]) {
|
|
||||||
url = (match[3] ? 'http://' : 'mailto:') + url;
|
|
||||||
}
|
|
||||||
i = match.index;
|
|
||||||
addText(raw.substr(0, i));
|
|
||||||
addLink(url, match[0].replace(MAILTO_REGEXP, ''));
|
|
||||||
raw = raw.substring(i + match[0].length);
|
|
||||||
}
|
|
||||||
addText(raw);
|
|
||||||
return $sanitize(html.join(''));
|
|
||||||
|
|
||||||
function addText(text) {
|
|
||||||
if (!text) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
html.push(sanitizeText(text));
|
|
||||||
}
|
|
||||||
|
|
||||||
function addLink(url, text) {
|
|
||||||
var key, linkAttributes = attributesFn(url);
|
|
||||||
html.push('<a ');
|
|
||||||
|
|
||||||
for (key in linkAttributes) {
|
|
||||||
html.push(key + '="' + linkAttributes[key] + '" ');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDefined(target) && !('target' in linkAttributes)) {
|
|
||||||
html.push('target="',
|
|
||||||
target,
|
|
||||||
'" ');
|
|
||||||
}
|
|
||||||
html.push('href="',
|
|
||||||
url.replace(/"/g, '"'),
|
|
||||||
'">');
|
|
||||||
addText(text);
|
|
||||||
html.push('</a>');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}]);
|
|
||||||
|
|
||||||
|
|
||||||
})(window, window.angular);
|
|
|
@ -1,18 +0,0 @@
|
||||||
/*
|
|
||||||
AngularJS v1.8.0
|
|
||||||
(c) 2010-2020 Google, Inc. http://angularjs.org
|
|
||||||
License: MIT
|
|
||||||
*/
|
|
||||||
(function(s,c){'use strict';function P(c){var h=[];C(h,E).chars(c);return h.join("")}var D=c.$$minErr("$sanitize"),F,h,G,H,I,q,E,J,K,C;c.module("ngSanitize",[]).provider("$sanitize",function(){function f(a,e){return B(a.split(","),e)}function B(a,e){var d={},b;for(b=0;b<a.length;b++)d[e?q(a[b]):a[b]]=!0;return d}function t(a,e){e&&e.length&&h(a,B(e))}function Q(a){for(var e={},d=0,b=a.length;d<b;d++){var k=a[d];e[k.name]=k.value}return e}function L(a){return a.replace(/&/g,"&").replace(z,function(a){var d=
|
|
||||||
a.charCodeAt(0);a=a.charCodeAt(1);return"&#"+(1024*(d-55296)+(a-56320)+65536)+";"}).replace(u,function(a){return"&#"+a.charCodeAt(0)+";"}).replace(/</g,"<").replace(/>/g,">")}function A(a){for(;a;){if(a.nodeType===s.Node.ELEMENT_NODE)for(var e=a.attributes,d=0,b=e.length;d<b;d++){var k=e[d],g=k.name.toLowerCase();if("xmlns:ns1"===g||0===g.lastIndexOf("ns1:",0))a.removeAttributeNode(k),d--,b--}(e=a.firstChild)&&A(e);a=v("nextSibling",a)}}function v(a,e){var d=e[a];if(d&&J.call(e,d))throw D("elclob",
|
|
||||||
e.outerHTML||e.outerText);return d}var y=!1,g=!1;this.$get=["$$sanitizeUri",function(a){y=!0;g&&h(m,l);return function(e){var d=[];K(e,C(d,function(b,d){return!/^unsafe:/.test(a(b,d))}));return d.join("")}}];this.enableSvg=function(a){return I(a)?(g=a,this):g};this.addValidElements=function(a){y||(H(a)&&(a={htmlElements:a}),t(l,a.svgElements),t(r,a.htmlVoidElements),t(m,a.htmlVoidElements),t(m,a.htmlElements));return this};this.addValidAttrs=function(a){y||h(M,B(a,!0));return this};F=c.bind;h=c.extend;
|
|
||||||
G=c.forEach;H=c.isArray;I=c.isDefined;q=c.$$lowercase;E=c.noop;K=function(a,e){null===a||void 0===a?a="":"string"!==typeof a&&(a=""+a);var d=N(a);if(!d)return"";var b=5;do{if(0===b)throw D("uinput");b--;a=d.innerHTML;d=N(a)}while(a!==d.innerHTML);for(b=d.firstChild;b;){switch(b.nodeType){case 1:e.start(b.nodeName.toLowerCase(),Q(b.attributes));break;case 3:e.chars(b.textContent)}var k;if(!(k=b.firstChild)&&(1===b.nodeType&&e.end(b.nodeName.toLowerCase()),k=v("nextSibling",b),!k))for(;null==k;){b=
|
|
||||||
v("parentNode",b);if(b===d)break;k=v("nextSibling",b);1===b.nodeType&&e.end(b.nodeName.toLowerCase())}b=k}for(;b=d.firstChild;)d.removeChild(b)};C=function(a,e){var d=!1,b=F(a,a.push);return{start:function(a,g){a=q(a);!d&&w[a]&&(d=a);d||!0!==m[a]||(b("<"),b(a),G(g,function(d,g){var c=q(g),f="img"===a&&"src"===c||"background"===c;!0!==M[c]||!0===O[c]&&!e(d,f)||(b(" "),b(g),b('="'),b(L(d)),b('"'))}),b(">"))},end:function(a){a=q(a);d||!0!==m[a]||!0===r[a]||(b("</"),b(a),b(">"));a==d&&(d=!1)},chars:function(a){d||
|
|
||||||
b(L(a))}}};J=s.Node.prototype.contains||function(a){return!!(this.compareDocumentPosition(a)&16)};var z=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,u=/([^#-~ |!])/g,r=f("area,br,col,hr,img,wbr"),x=f("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),p=f("rp,rt"),n=h({},p,x),x=h({},x,f("address,article,aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul")),p=h({},p,f("a,abbr,acronym,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small,span,strike,strong,sub,sup,time,tt,u,var")),
|
|
||||||
l=f("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,stop,svg,switch,text,title,tspan"),w=f("script,style"),m=h({},r,x,p,n),O=f("background,cite,href,longdesc,src,xlink:href,xml:base"),n=f("abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,valign,value,vspace,width"),
|
|
||||||
p=f("accent-height,accumulate,additive,alphabetic,arabic-form,ascent,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan",
|
|
||||||
!0),M=h({},O,p,n),N=function(a,e){function d(b){b="<remove></remove>"+b;try{var d=(new a.DOMParser).parseFromString(b,"text/html").body;d.firstChild.remove();return d}catch(e){}}function b(a){c.innerHTML=a;e.documentMode&&A(c);return c}var g;if(e&&e.implementation)g=e.implementation.createHTMLDocument("inert");else throw D("noinert");var c=(g.documentElement||g.getDocumentElement()).querySelector("body");c.innerHTML='<svg><g onload="this.parentNode.remove()"></g></svg>';return c.querySelector("svg")?
|
|
||||||
(c.innerHTML='<svg><p><style><img src="</style><img src=x onerror=alert(1)//">',c.querySelector("svg img")?d:b):function(b){b="<remove></remove>"+b;try{b=encodeURI(b)}catch(d){return}var e=new a.XMLHttpRequest;e.responseType="document";e.open("GET","data:text/html;charset=utf-8,"+b,!1);e.send(null);b=e.response.body;b.firstChild.remove();return b}}(s,s.document)}).info({angularVersion:"1.8.0"});c.module("ngSanitize").filter("linky",["$sanitize",function(f){var h=/((s?ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,
|
|
||||||
t=/^mailto:/i,q=c.$$minErr("linky"),s=c.isDefined,A=c.isFunction,v=c.isObject,y=c.isString;return function(c,z,u){function r(c){c&&l.push(P(c))}function x(c,g){var f,a=p(c);l.push("<a ");for(f in a)l.push(f+'="'+a[f]+'" ');!s(z)||"target"in a||l.push('target="',z,'" ');l.push('href="',c.replace(/"/g,"""),'">');r(g);l.push("</a>")}if(null==c||""===c)return c;if(!y(c))throw q("notstring",c);for(var p=A(u)?u:v(u)?function(){return u}:function(){return{}},n=c,l=[],w,m;c=n.match(h);)w=c[0],c[2]||
|
|
||||||
c[4]||(w=(c[3]?"http://":"mailto:")+w),m=c.index,r(n.substr(0,m)),x(w,c[0].replace(t,"")),n=n.substring(m+c[0].length);r(n);return f(l.join(""))}}])})(window,window.angular);
|
|
||||||
//# sourceMappingURL=angular-sanitize.min.js.map
|
|
File diff suppressed because one or more lines are too long
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"name": "angular-sanitize",
|
|
||||||
"version": "1.8.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "./angular-sanitize.js",
|
|
||||||
"ignore": [],
|
|
||||||
"dependencies": {
|
|
||||||
"angular": "1.8.0"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
require('./angular-sanitize');
|
|
||||||
module.exports = 'ngSanitize';
|
|
|
@ -1,63 +0,0 @@
|
||||||
{
|
|
||||||
"_from": "angular-sanitize@1.8.0",
|
|
||||||
"_id": "angular-sanitize@1.8.0",
|
|
||||||
"_inBundle": false,
|
|
||||||
"_integrity": "sha512-j5GiOPCvfcDWK5svEOVoPb11X3UDVy/mdHPRWuy14Iyw86xaq+Bb+x/em2sAOa5MQQeY5ciLXbF3RRp8iCKcNg==",
|
|
||||||
"_location": "/angular-sanitize",
|
|
||||||
"_phantomChildren": {},
|
|
||||||
"_requested": {
|
|
||||||
"type": "version",
|
|
||||||
"registry": true,
|
|
||||||
"raw": "angular-sanitize@1.8.0",
|
|
||||||
"name": "angular-sanitize",
|
|
||||||
"escapedName": "angular-sanitize",
|
|
||||||
"rawSpec": "1.8.0",
|
|
||||||
"saveSpec": null,
|
|
||||||
"fetchSpec": "1.8.0"
|
|
||||||
},
|
|
||||||
"_requiredBy": [
|
|
||||||
"/"
|
|
||||||
],
|
|
||||||
"_resolved": "https://registry.npmjs.org/angular-sanitize/-/angular-sanitize-1.8.0.tgz",
|
|
||||||
"_shasum": "9f80782d3afeec3bcc0bb92b3ca6f1f421cfbca6",
|
|
||||||
"_spec": "angular-sanitize@1.8.0",
|
|
||||||
"_where": "/home/abstractj/github/keycloak/themes/src/main/resources/theme/keycloak/common/resources",
|
|
||||||
"author": {
|
|
||||||
"name": "Angular Core Team",
|
|
||||||
"email": "angular-core+npm@google.com"
|
|
||||||
},
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/angular/angular.js/issues"
|
|
||||||
},
|
|
||||||
"bundleDependencies": false,
|
|
||||||
"deprecated": false,
|
|
||||||
"description": "AngularJS module for sanitizing HTML",
|
|
||||||
"homepage": "http://angularjs.org",
|
|
||||||
"jspm": {
|
|
||||||
"shim": {
|
|
||||||
"angular-sanitize": {
|
|
||||||
"deps": [
|
|
||||||
"angular"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"angular",
|
|
||||||
"framework",
|
|
||||||
"browser",
|
|
||||||
"html",
|
|
||||||
"client-side"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "index.js",
|
|
||||||
"name": "angular-sanitize",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/angular/angular.js.git"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"version": "1.8.0"
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
# angular-translate-loader-url (bower shadow repository)
|
|
||||||
|
|
||||||
This is the _Bower shadow_ repository for *angular-translate-loader-url*.
|
|
||||||
|
|
||||||
## Bugs and issues
|
|
||||||
|
|
||||||
Please file any issues and bugs in our main repository at [angular-translate/angular-translate](https://github.com/angular-translate/angular-translate/issues).
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### via Bower
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ bower install angular-translate-loader-url
|
|
||||||
```
|
|
||||||
|
|
||||||
### via NPM
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ npm install angular-translate-loader-url
|
|
||||||
```
|
|
||||||
|
|
||||||
### via cdnjs
|
|
||||||
|
|
||||||
Please have a look at https://cdnjs.com/libraries/angular-translate-loader-url for specific versions.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
Licensed under MIT. See more details at [angular-translate/angular-translate](https://github.com/angular-translate/angular-translate).
|
|
|
@ -1,73 +0,0 @@
|
||||||
/*!
|
|
||||||
* angular-translate - v2.18.2 - 2020-01-04
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
|
|
||||||
*/
|
|
||||||
(function (root, factory) {
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
// AMD. Register as an anonymous module unless amdModuleId is set
|
|
||||||
define([], function () {
|
|
||||||
return (factory());
|
|
||||||
});
|
|
||||||
} else if (typeof module === 'object' && module.exports) {
|
|
||||||
// Node. Does not work with strict CommonJS, but
|
|
||||||
// only CommonJS-like environments that support module.exports,
|
|
||||||
// like Node.
|
|
||||||
module.exports = factory();
|
|
||||||
} else {
|
|
||||||
factory();
|
|
||||||
}
|
|
||||||
}(this, function () {
|
|
||||||
|
|
||||||
$translateUrlLoader.$inject = ['$q', '$http'];
|
|
||||||
angular.module('pascalprecht.translate')
|
|
||||||
/**
|
|
||||||
* @ngdoc object
|
|
||||||
* @name pascalprecht.translate.$translateUrlLoader
|
|
||||||
* @requires $q
|
|
||||||
* @requires $http
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Creates a loading function for a typical dynamic url pattern:
|
|
||||||
* "locale.php?lang=en_US", "locale.php?lang=de_DE", "locale.php?language=nl_NL" etc.
|
|
||||||
* Prefixing the specified url, the current requested, language id will be applied
|
|
||||||
* with "?{queryParameter}={key}".
|
|
||||||
* Using this service, the response of these urls must be an object of
|
|
||||||
* key-value pairs.
|
|
||||||
*
|
|
||||||
* @param {object} options Options object, which gets the url, key and
|
|
||||||
* optional queryParameter ('lang' is used by default).
|
|
||||||
*/
|
|
||||||
.factory('$translateUrlLoader', $translateUrlLoader);
|
|
||||||
|
|
||||||
function $translateUrlLoader($q, $http) {
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
return function (options) {
|
|
||||||
|
|
||||||
if (!options || !options.url) {
|
|
||||||
throw new Error('Couldn\'t use urlLoader since no url is given!');
|
|
||||||
}
|
|
||||||
|
|
||||||
var requestParams = {};
|
|
||||||
|
|
||||||
requestParams[options.queryParameter || 'lang'] = options.key;
|
|
||||||
|
|
||||||
return $http(angular.extend({
|
|
||||||
url: options.url,
|
|
||||||
params: requestParams,
|
|
||||||
method: 'GET'
|
|
||||||
}, options.$http))
|
|
||||||
.then(function(result) {
|
|
||||||
return result.data;
|
|
||||||
}, function () {
|
|
||||||
return $q.reject(options.key);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
$translateUrlLoader.displayName = '$translateUrlLoader';
|
|
||||||
return 'pascalprecht.translate';
|
|
||||||
|
|
||||||
}));
|
|
|
@ -1,6 +0,0 @@
|
||||||
/*!
|
|
||||||
* angular-translate - v2.18.2 - 2020-01-04
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
|
|
||||||
*/
|
|
||||||
!function(e,t){"function"==typeof define&&define.amd?define([],function(){return t()}):"object"==typeof module&&module.exports?module.exports=t():t()}(0,function(){function e(r,n){"use strict";return function(e){if(!e||!e.url)throw new Error("Couldn't use urlLoader since no url is given!");var t={};return t[e.queryParameter||"lang"]=e.key,n(angular.extend({url:e.url,params:t,method:"GET"},e.$http)).then(function(e){return e.data},function(){return r.reject(e.key)})}}return e.$inject=["$q","$http"],angular.module("pascalprecht.translate").factory("$translateUrlLoader",e),e.displayName="$translateUrlLoader","pascalprecht.translate"});
|
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"name": "angular-translate-loader-url",
|
|
||||||
"description": "A plugin for Angular Translate",
|
|
||||||
"version": "2.18.2",
|
|
||||||
"main": "./angular-translate-loader-url.js",
|
|
||||||
"ignore": [],
|
|
||||||
"author": "Pascal Precht",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"angular-translate": "~2.18.2"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
{
|
|
||||||
"_from": "angular-translate-loader-url@2.18.2",
|
|
||||||
"_id": "angular-translate-loader-url@2.18.2",
|
|
||||||
"_inBundle": false,
|
|
||||||
"_integrity": "sha512-jaRF7F5xB6TgtTkDlmpV7DhjTXgJlN2FWQTFc47gM/xynB/nMw6TpNAXnJ/5KZlWSI5IDpisCp6gYeyLucZBgg==",
|
|
||||||
"_location": "/angular-translate-loader-url",
|
|
||||||
"_phantomChildren": {},
|
|
||||||
"_requested": {
|
|
||||||
"type": "version",
|
|
||||||
"registry": true,
|
|
||||||
"raw": "angular-translate-loader-url@2.18.2",
|
|
||||||
"name": "angular-translate-loader-url",
|
|
||||||
"escapedName": "angular-translate-loader-url",
|
|
||||||
"rawSpec": "2.18.2",
|
|
||||||
"saveSpec": null,
|
|
||||||
"fetchSpec": "2.18.2"
|
|
||||||
},
|
|
||||||
"_requiredBy": [
|
|
||||||
"/"
|
|
||||||
],
|
|
||||||
"_resolved": "https://registry.npmjs.org/angular-translate-loader-url/-/angular-translate-loader-url-2.18.2.tgz",
|
|
||||||
"_shasum": "a85004b53644d15cbb876212ff7db4c66e301d1b",
|
|
||||||
"_spec": "angular-translate-loader-url@2.18.2",
|
|
||||||
"_where": "/home/abstractj/github/keycloak/themes/src/main/resources/theme/keycloak/common/resources",
|
|
||||||
"author": {
|
|
||||||
"name": "Pascal Precht"
|
|
||||||
},
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/angular-translate/angular-translate/issues"
|
|
||||||
},
|
|
||||||
"bundleDependencies": false,
|
|
||||||
"dependencies": {
|
|
||||||
"angular-translate": "~2.18.2"
|
|
||||||
},
|
|
||||||
"deprecated": false,
|
|
||||||
"description": "Creates a loading function for a typical dynamic url pattern: \"locale.php?lang=en_US\", \"locale.php?lang=de_DE\", \"locale.php?language=nl_NL\" etc. Prefixing the specified url, the current requested, language id will be applied with \"?{queryParameter}={key}\". Using this service, the response of these urls must be an object of key-value pairs.",
|
|
||||||
"homepage": "https://angular-translate.github.io",
|
|
||||||
"keywords": [
|
|
||||||
"angular",
|
|
||||||
"translate",
|
|
||||||
"loader"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "angular-translate-loader-url.js",
|
|
||||||
"name": "angular-translate-loader-url",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/angular-translate/bower-angular-translate-loader-url.git"
|
|
||||||
},
|
|
||||||
"version": "2.18.2"
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
12.14
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2013-2017 The angular-translate team and Pascal Precht
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
|
@ -1,90 +0,0 @@
|
||||||
# [![angular-translate](https://raw.github.com/angular-translate/angular-translate/canary/identity/logo/angular-translate-alternative/angular-translate_alternative_medium2.png)](http://angular-translate.github.io)
|
|
||||||
|
|
||||||
[![Greenkeeper badge](https://badges.greenkeeper.io/angular-translate/angular-translate.svg)](https://greenkeeper.io/)
|
|
||||||
|
|
||||||
![Bower](https://img.shields.io/bower/v/angular-translate.svg) [![NPM](https://img.shields.io/npm/v/angular-translate.svg)](https://www.npmjs.com/package/angular-translate) [![cdnjs](https://img.shields.io/cdnjs/v/angular-translate.svg)](https://cdnjs.com/libraries/angular-translate) [![Build Status](https://img.shields.io/travis/angular-translate/angular-translate.svg)](https://travis-ci.org/angular-translate/angular-translate) ![License](https://img.shields.io/npm/l/angular-translate.svg) ![Code Climate](https://img.shields.io/codeclimate/github/angular-translate/angular-translate.svg) ![Code Coverage](https://img.shields.io/codeclimate/coverage/github/angular-translate/angular-translate.svg)
|
|
||||||
|
|
||||||
This is the repository for angular-translate.
|
|
||||||
|
|
||||||
angular-translate is a JavaScript translation library for AngularJS 1.x app.
|
|
||||||
|
|
||||||
For more information about the angular-translate project, please visit our [website](https://angular-translate.github.io).
|
|
||||||
|
|
||||||
## Status
|
|
||||||
| Branch | Status |
|
|
||||||
| ------------- |:-------------:|
|
|
||||||
| master | [![Build Status](https://travis-ci.org/angular-translate/angular-translate.svg?branch=master)](https://travis-ci.org/angular-translate/angular-translate) |
|
|
||||||
| canary |[![Build Status](https://travis-ci.org/angular-translate/angular-translate.svg?branch=canary)](https://travis-ci.org/angular-translate/angular-translate) |
|
|
||||||
|
|
||||||
## Install
|
|
||||||
We strongly *recommend* using a package manager like NPM and Bower, or even variants like Yarn or jspm.
|
|
||||||
|
|
||||||
### NPM
|
|
||||||
```
|
|
||||||
npm install --save-dev angular-translate
|
|
||||||
```
|
|
||||||
|
|
||||||
### Bower
|
|
||||||
```
|
|
||||||
bower install --save-dev angular-translate
|
|
||||||
```
|
|
||||||
|
|
||||||
For more information please visit [chapter "Installation" at our website](https://angular-translate.github.io/docs/#/guide/00_installation).
|
|
||||||
|
|
||||||
## Get started
|
|
||||||
Check out the [chapter "Getting started" at our website](https://angular-translate.github.io/docs/#/guide/02_getting-started).
|
|
||||||
|
|
||||||
## Get support
|
|
||||||
Most of the time, we are getting support questions of invalid configurations. We encourage everyone to have a look at our [documentation website](https://angular-translate.github.io/docs/#/guide). If you think the documentation is not correct (bug) or should be optimized (enhancement) please file an issue.
|
|
||||||
|
|
||||||
If you are still having difficulty after looking over your configuration carefully, please post a question to [StackOverflow with a specific tag](http://stackoverflow.com/questions/tagged/angular-translate). Especially if the question are related to AngularJS or even JavaScript/browser basic technologies (maybe your issue is not related to angular-translate after all).
|
|
||||||
|
|
||||||
If you have discovered a bug or have a feature suggestion, feel free to create an issue on GitHub. Please follow the guideline within the issue template. See also next headline.
|
|
||||||
|
|
||||||
*Please note: We cannot provide support for neither JavaScript nor AngularJS itself. In both cases, a platform like StackOverflow is much more ideal.*
|
|
||||||
|
|
||||||
# Contribute
|
|
||||||
We got a lot of great feedback from the community so far! More and more people
|
|
||||||
use this module and they are always thankful for it and the awesome support they
|
|
||||||
get. I just want to make sure that you guys know: All this wouldn't have been
|
|
||||||
possible without these [great contributors](https://github.com/angular-translate/angular-translate/contributors)
|
|
||||||
and everybody who comes with new ideas and feature requests! So **THANK YOU**!
|
|
||||||
|
|
||||||
Contributing to <code>angular-translate</code> is fairly easy.
|
|
||||||
|
|
||||||
[This document](CONTRIBUTING.md) shows you how to
|
|
||||||
get the project, run all provided tests and generate a production ready build.
|
|
||||||
|
|
||||||
|
|
||||||
## Public talks
|
|
||||||
[![Dutch AngularJS Meetup 2013](presentation.png)](https://www.youtube.com/watch?v=9CWifOK_Wi8)
|
|
||||||
[![Kod.io 2014](presentation2.png)](https://www.youtube.com/watch?v=C7xqaExvaQ4)
|
|
||||||
|
|
||||||
### Links
|
|
||||||
* Website [angular-translate.github.io](https://angular-translate.github.io/)
|
|
||||||
* API Reference [angular-translate.github.io/docs/#/api](https://angular-translate.github.io/docs/#/api)
|
|
||||||
* [Contribution Guidelines](https://github.com/angular-translate/angular-translate/blob/master/CONTRIBUTING.md)
|
|
||||||
|
|
||||||
### Useful resources
|
|
||||||
There are some very useful things on the web that might be interesting for you,
|
|
||||||
so make sure to check this list.
|
|
||||||
|
|
||||||
- [Tutorial on ng-newsletter.com](http://ng-newsletter.com/posts/angular-translate.html)
|
|
||||||
- [Examples and demos](https://github.com/angular-translate/angular-translate/wiki/Demos) - Currently on plnkr.co
|
|
||||||
- [Tutorial on angular.de](http://angular.de/artikel/angularjs-i18n-ng-translate) - German article
|
|
||||||
- [angular-translate on GitHub](https://github.com/angular-translate/angular-translate) - The GitHub repository
|
|
||||||
- [angular-translate on ngmodules.org](http://ngmodules.org/modules/angular-translate)
|
|
||||||
- [angular-translate mailinglist](https://groups.google.com/forum/#!forum/angular-translate) - Discuss, ask et al!
|
|
||||||
- [angular-translate-quality](https://www.npmjs.com/package/angular-translate-quality) - Quality check at build time
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
### Unit tests
|
|
||||||
|
|
||||||
Note: Check that dependencies are be installed (`npm install`).
|
|
||||||
|
|
||||||
The *unit tests* are available with `npm test` which is actually a shortcut for `grunt test`. It performs tests under the current primary target version of AngularJS. Use `npm run-script test-scopes` for testing other scoped versions as well.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
Licensed under MIT.
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*!
|
|
||||||
* angular-translate - v2.18.2 - 2020-01-04
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
|
|
||||||
*/
|
|
||||||
(function (root, factory) {
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
// AMD. Register as an anonymous module unless amdModuleId is set
|
|
||||||
define([], function () {
|
|
||||||
return (factory());
|
|
||||||
});
|
|
||||||
} else if (typeof module === 'object' && module.exports) {
|
|
||||||
// Node. Does not work with strict CommonJS, but
|
|
||||||
// only CommonJS-like environments that support module.exports,
|
|
||||||
// like Node.
|
|
||||||
module.exports = factory();
|
|
||||||
} else {
|
|
||||||
factory();
|
|
||||||
}
|
|
||||||
}(this, function () {
|
|
||||||
|
|
||||||
$translateMissingTranslationHandlerLog.$inject = ['$log'];
|
|
||||||
angular.module('pascalprecht.translate')
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc object
|
|
||||||
* @name pascalprecht.translate.$translateMissingTranslationHandlerLog
|
|
||||||
* @requires $log
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Uses angular's `$log` service to give a warning when trying to translate a
|
|
||||||
* translation id which doesn't exist.
|
|
||||||
*
|
|
||||||
* @returns {function} Handler function
|
|
||||||
*/
|
|
||||||
.factory('$translateMissingTranslationHandlerLog', $translateMissingTranslationHandlerLog);
|
|
||||||
|
|
||||||
function $translateMissingTranslationHandlerLog ($log) {
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
return function (translationId) {
|
|
||||||
$log.warn('Translation for ' + translationId + ' doesn\'t exist');
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
$translateMissingTranslationHandlerLog.displayName = '$translateMissingTranslationHandlerLog';
|
|
||||||
return 'pascalprecht.translate';
|
|
||||||
|
|
||||||
}));
|
|
|
@ -1,6 +0,0 @@
|
||||||
/*!
|
|
||||||
* angular-translate - v2.18.2 - 2020-01-04
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
|
|
||||||
*/
|
|
||||||
!function(n,t){"function"==typeof define&&define.amd?define([],function(){return t()}):"object"==typeof module&&module.exports?module.exports=t():t()}(0,function(){function n(t){"use strict";return function(n){t.warn("Translation for "+n+" doesn't exist")}}return n.$inject=["$log"],angular.module("pascalprecht.translate").factory("$translateMissingTranslationHandlerLog",n),n.displayName="$translateMissingTranslationHandlerLog","pascalprecht.translate"});
|
|
|
@ -1,197 +0,0 @@
|
||||||
/*!
|
|
||||||
* angular-translate - v2.18.2 - 2020-01-04
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
|
|
||||||
*/
|
|
||||||
(function (root, factory) {
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
// AMD. Register as an anonymous module unless amdModuleId is set
|
|
||||||
define(["messageformat"], function (a0) {
|
|
||||||
return (factory(a0));
|
|
||||||
});
|
|
||||||
} else if (typeof module === 'object' && module.exports) {
|
|
||||||
// Node. Does not work with strict CommonJS, but
|
|
||||||
// only CommonJS-like environments that support module.exports,
|
|
||||||
// like Node.
|
|
||||||
module.exports = factory(require("messageformat"));
|
|
||||||
} else {
|
|
||||||
factory(root["MessageFormat"]);
|
|
||||||
}
|
|
||||||
}(this, function (MessageFormat) {
|
|
||||||
|
|
||||||
angular.module('pascalprecht.translate')
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc property
|
|
||||||
* @name pascalprecht.translate.TRANSLATE_MF_INTERPOLATION_CACHE
|
|
||||||
* @requires TRANSLATE_MF_INTERPOLATION_CACHE
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Uses MessageFormat.js to interpolate strings against some values.
|
|
||||||
*/
|
|
||||||
.constant('TRANSLATE_MF_INTERPOLATION_CACHE', '$translateMessageFormatInterpolation')
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc object
|
|
||||||
* @name pascalprecht.translate.$translateMessageFormatInterpolationProvider
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Configurations for $translateMessageFormatInterpolation
|
|
||||||
*/
|
|
||||||
.provider('$translateMessageFormatInterpolation', $translateMessageFormatInterpolationProvider);
|
|
||||||
|
|
||||||
function $translateMessageFormatInterpolationProvider() {
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var configurer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translateMessageFormatInterpolationProvider#messageFormatConfigurer
|
|
||||||
* @methodOf pascalprecht.translate.$translateMessageFormatInterpolationProvider
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Defines an optional configurer for the MessageFormat instance.
|
|
||||||
*
|
|
||||||
* Note: This hook will be called whenever a new instance of MessageFormat will be created.
|
|
||||||
*
|
|
||||||
* @param {function} fn callback with the instance as argument
|
|
||||||
*/
|
|
||||||
this.messageFormatConfigurer = function (fn) {
|
|
||||||
configurer = fn;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc object
|
|
||||||
* @name pascalprecht.translate.$translateMessageFormatInterpolation
|
|
||||||
* @requires pascalprecht.translate.TRANSLATE_MF_INTERPOLATION_CACHE
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Uses MessageFormat.js to interpolate strings against some values.
|
|
||||||
*
|
|
||||||
* Be aware to configure a proper sanitization strategy.
|
|
||||||
*
|
|
||||||
* See also:
|
|
||||||
* * {@link pascalprecht.translate.$translateSanitization}
|
|
||||||
* * {@link https://github.com/SlexAxton/messageformat.js}
|
|
||||||
*
|
|
||||||
* @return {object} $translateMessageFormatInterpolation Interpolator service
|
|
||||||
*/
|
|
||||||
this.$get = ['$translateSanitization', '$cacheFactory', 'TRANSLATE_MF_INTERPOLATION_CACHE', function ($translateSanitization, $cacheFactory, TRANSLATE_MF_INTERPOLATION_CACHE) {
|
|
||||||
return $translateMessageFormatInterpolation($translateSanitization, $cacheFactory, TRANSLATE_MF_INTERPOLATION_CACHE, configurer);
|
|
||||||
}];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function $translateMessageFormatInterpolation($translateSanitization, $cacheFactory, TRANSLATE_MF_INTERPOLATION_CACHE, messageFormatConfigurer) {
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var $translateInterpolator = {},
|
|
||||||
$cache = $cacheFactory.get(TRANSLATE_MF_INTERPOLATION_CACHE),
|
|
||||||
// instantiate with default locale (which is 'en')
|
|
||||||
$mf = new MessageFormat('en'),
|
|
||||||
$identifier = 'messageformat';
|
|
||||||
|
|
||||||
if (angular.isFunction(messageFormatConfigurer)) {
|
|
||||||
messageFormatConfigurer($mf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$cache) {
|
|
||||||
// create cache if it doesn't exist already
|
|
||||||
$cache = $cacheFactory(TRANSLATE_MF_INTERPOLATION_CACHE);
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache.put('en', $mf);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translateMessageFormatInterpolation#setLocale
|
|
||||||
* @methodOf pascalprecht.translate.$translateMessageFormatInterpolation
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Sets current locale (this is currently not use in this interpolation).
|
|
||||||
*
|
|
||||||
* @param {string} locale Language key or locale.
|
|
||||||
*/
|
|
||||||
$translateInterpolator.setLocale = function (locale) {
|
|
||||||
$mf = $cache.get(locale);
|
|
||||||
if (!$mf) {
|
|
||||||
$mf = new MessageFormat(locale);
|
|
||||||
if (angular.isFunction(messageFormatConfigurer)) {
|
|
||||||
messageFormatConfigurer($mf);
|
|
||||||
}
|
|
||||||
$cache.put(locale, $mf);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translateMessageFormatInterpolation#getInterpolationIdentifier
|
|
||||||
* @methodOf pascalprecht.translate.$translateMessageFormatInterpolation
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Returns an identifier for this interpolation service.
|
|
||||||
*
|
|
||||||
* @returns {string} $identifier
|
|
||||||
*/
|
|
||||||
$translateInterpolator.getInterpolationIdentifier = function () {
|
|
||||||
return $identifier;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated will be removed in 3.0
|
|
||||||
* @see {@link pascalprecht.translate.$translateSanitization}
|
|
||||||
*/
|
|
||||||
$translateInterpolator.useSanitizeValueStrategy = function (value) {
|
|
||||||
$translateSanitization.useStrategy(value);
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translateMessageFormatInterpolation#interpolate
|
|
||||||
* @methodOf pascalprecht.translate.$translateMessageFormatInterpolation
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Interpolates given string against given interpolate params using MessageFormat.js.
|
|
||||||
*
|
|
||||||
* @returns {string} interpolated string.
|
|
||||||
*/
|
|
||||||
$translateInterpolator.interpolate = function (string, interpolationParams, context, sanitizeStrategy) {
|
|
||||||
interpolationParams = interpolationParams || {};
|
|
||||||
interpolationParams = $translateSanitization.sanitize(interpolationParams, 'params', sanitizeStrategy);
|
|
||||||
|
|
||||||
var compiledFunction = $cache.get('mf:' + string);
|
|
||||||
|
|
||||||
// if given string wasn't compiled yet, we do so now and never have to do it again
|
|
||||||
if (!compiledFunction) {
|
|
||||||
|
|
||||||
// Ensure explicit type if possible
|
|
||||||
// MessageFormat checks the actual type (i.e. for amount based conditions)
|
|
||||||
for (var key in interpolationParams) {
|
|
||||||
if (interpolationParams.hasOwnProperty(key)) {
|
|
||||||
// ensure number
|
|
||||||
var number = parseInt(interpolationParams[key], 10);
|
|
||||||
if (angular.isNumber(number) && ('' + number) === interpolationParams[key]) {
|
|
||||||
interpolationParams[key] = number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compiledFunction = $mf.compile(string);
|
|
||||||
$cache.put('mf:' + string, compiledFunction);
|
|
||||||
}
|
|
||||||
|
|
||||||
var interpolatedText = compiledFunction(interpolationParams);
|
|
||||||
return $translateSanitization.sanitize(interpolatedText, 'text', sanitizeStrategy);
|
|
||||||
};
|
|
||||||
|
|
||||||
return $translateInterpolator;
|
|
||||||
}
|
|
||||||
|
|
||||||
$translateMessageFormatInterpolation.displayName = '$translateMessageFormatInterpolation';
|
|
||||||
return 'pascalprecht.translate';
|
|
||||||
|
|
||||||
}));
|
|
|
@ -1,6 +0,0 @@
|
||||||
/*!
|
|
||||||
* angular-translate - v2.18.2 - 2020-01-04
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
|
|
||||||
*/
|
|
||||||
!function(t,e){"function"==typeof define&&define.amd?define(["messageformat"],function(t){return e(t)}):"object"==typeof module&&module.exports?module.exports=e(require("messageformat")):e(t.MessageFormat)}(this,function(r){function i(u,t,e,n){"use strict";var a={},c=t.get(e),f=new r("en");return angular.isFunction(n)&&n(f),c||(c=t(e)),c.put("en",f),a.setLocale=function(t){(f=c.get(t))||(f=new r(t),angular.isFunction(n)&&n(f),c.put(t,f))},a.getInterpolationIdentifier=function(){return"messageformat"},a.useSanitizeValueStrategy=function(t){return u.useStrategy(t),this},a.interpolate=function(t,e,n,a){e=e||{},e=u.sanitize(e,"params",a);var r=c.get("mf:"+t);if(!r){for(var i in e)if(e.hasOwnProperty(i)){var o=parseInt(e[i],10);angular.isNumber(o)&&""+o===e[i]&&(e[i]=o)}r=f.compile(t),c.put("mf:"+t,r)}var s=r(e);return u.sanitize(s,"text",a)},a}return angular.module("pascalprecht.translate").constant("TRANSLATE_MF_INTERPOLATION_CACHE","$translateMessageFormatInterpolation").provider("$translateMessageFormatInterpolation",function(){"use strict";var a;this.messageFormatConfigurer=function(t){a=t},this.$get=["$translateSanitization","$cacheFactory","TRANSLATE_MF_INTERPOLATION_CACHE",function(t,e,n){return i(t,e,n,a)}]}),i.displayName="$translateMessageFormatInterpolation","pascalprecht.translate"});
|
|
|
@ -1,585 +0,0 @@
|
||||||
/*!
|
|
||||||
* angular-translate - v2.18.2 - 2020-01-04
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
|
|
||||||
*/
|
|
||||||
(function (root, factory) {
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
// AMD. Register as an anonymous module unless amdModuleId is set
|
|
||||||
define([], function () {
|
|
||||||
return (factory());
|
|
||||||
});
|
|
||||||
} else if (typeof module === 'object' && module.exports) {
|
|
||||||
// Node. Does not work with strict CommonJS, but
|
|
||||||
// only CommonJS-like environments that support module.exports,
|
|
||||||
// like Node.
|
|
||||||
module.exports = factory();
|
|
||||||
} else {
|
|
||||||
factory();
|
|
||||||
}
|
|
||||||
}(this, function () {
|
|
||||||
|
|
||||||
angular.module('pascalprecht.translate')
|
|
||||||
/**
|
|
||||||
* @ngdoc object
|
|
||||||
* @name pascalprecht.translate.$translatePartialLoaderProvider
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* By using a $translatePartialLoaderProvider you can configure a list of a needed
|
|
||||||
* translation parts directly during the configuration phase of your application's
|
|
||||||
* lifetime. All parts you add by using this provider would be loaded by
|
|
||||||
* angular-translate at the startup as soon as possible.
|
|
||||||
*/
|
|
||||||
.provider('$translatePartialLoader', $translatePartialLoader);
|
|
||||||
|
|
||||||
function $translatePartialLoader() {
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constructor
|
|
||||||
* @name Part
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Represents Part object to add and set parts at runtime.
|
|
||||||
*/
|
|
||||||
function Part(name, priority, urlTemplate) {
|
|
||||||
this.name = name;
|
|
||||||
this.isActive = true;
|
|
||||||
this.tables = {};
|
|
||||||
this.priority = priority || 0;
|
|
||||||
this.langPromises = {};
|
|
||||||
this.urlTemplate = urlTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @name parseUrl
|
|
||||||
* @method
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Returns a parsed url template string and replaces given target lang
|
|
||||||
* and part name it.
|
|
||||||
*
|
|
||||||
* @param {string|function} urlTemplate - Either a string containing an url pattern (with
|
|
||||||
* '{part}' and '{lang}') or a function(part, lang)
|
|
||||||
* returning a string.
|
|
||||||
* @param {string} targetLang - Language key for language to be used.
|
|
||||||
* @return {string} Parsed url template string
|
|
||||||
*/
|
|
||||||
Part.prototype.parseUrl = function (urlTemplate, targetLang) {
|
|
||||||
if (angular.isFunction(urlTemplate)) {
|
|
||||||
return urlTemplate(this.name, targetLang);
|
|
||||||
}
|
|
||||||
return urlTemplate.replace(/\{part\}/g, this.name).replace(/\{lang\}/g, targetLang);
|
|
||||||
};
|
|
||||||
|
|
||||||
Part.prototype.getTable = function (lang, $q, $http, $httpOptions, urlTemplate, errorHandler) {
|
|
||||||
|
|
||||||
//locals
|
|
||||||
var self = this;
|
|
||||||
var lastLangPromise = this.langPromises[lang];
|
|
||||||
var deferred = $q.defer();
|
|
||||||
|
|
||||||
//private helper helpers
|
|
||||||
var fetchData = function () {
|
|
||||||
return $http(
|
|
||||||
angular.extend({
|
|
||||||
method : 'GET',
|
|
||||||
url : self.parseUrl(self.urlTemplate || urlTemplate, lang)
|
|
||||||
},
|
|
||||||
$httpOptions)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//private helper
|
|
||||||
var handleNewData = function (data) {
|
|
||||||
self.tables[lang] = data;
|
|
||||||
deferred.resolve(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
//private helper
|
|
||||||
var rejectDeferredWithPartName = function () {
|
|
||||||
deferred.reject(self.name);
|
|
||||||
};
|
|
||||||
|
|
||||||
//private helper
|
|
||||||
var tryGettingThisTable = function () {
|
|
||||||
//data fetching logic
|
|
||||||
fetchData().then(
|
|
||||||
function (result) {
|
|
||||||
handleNewData(result.data);
|
|
||||||
},
|
|
||||||
function (errorResponse) {
|
|
||||||
if (errorHandler) {
|
|
||||||
errorHandler(self.name, lang, errorResponse).then(handleNewData, rejectDeferredWithPartName);
|
|
||||||
} else {
|
|
||||||
rejectDeferredWithPartName();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//loading logic
|
|
||||||
if (!this.tables[lang]) {
|
|
||||||
//let's try loading the data
|
|
||||||
if (!lastLangPromise) {
|
|
||||||
//this is the first request - just go ahead and hit the server
|
|
||||||
tryGettingThisTable();
|
|
||||||
} else {
|
|
||||||
//this is an additional request after one or more unfinished or failed requests
|
|
||||||
//chain the deferred off the previous request's promise so that this request conditionally executes
|
|
||||||
//if the previous request succeeds then the result will be passed through, but if it fails then this request will try again and hit the server
|
|
||||||
lastLangPromise.then(deferred.resolve, tryGettingThisTable);
|
|
||||||
}
|
|
||||||
//retain a reference to the last promise so we can continue the chain if another request is made before any succeed
|
|
||||||
//you can picture the promise chain as a singly-linked list (formed by the .then handler queues) that's traversed by the execution context
|
|
||||||
this.langPromises[lang] = deferred.promise;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//the part has already been loaded - if lastLangPromise is also undefined then the table has been populated using setPart
|
|
||||||
//this breaks the promise chain because we're not tying langDeferred's outcome to a previous call's promise handler queues, but we don't care because there's no asynchronous execution context to keep track of anymore
|
|
||||||
deferred.resolve(this.tables[lang]);
|
|
||||||
}
|
|
||||||
return deferred.promise;
|
|
||||||
};
|
|
||||||
|
|
||||||
var parts = {};
|
|
||||||
|
|
||||||
function hasPart(name) {
|
|
||||||
return Object.prototype.hasOwnProperty.call(parts, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isStringValid(str) {
|
|
||||||
return angular.isString(str) && str !== '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function isPartAvailable(name) {
|
|
||||||
if (!isStringValid(name)) {
|
|
||||||
throw new TypeError('Invalid type of a first argument, a non-empty string expected.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return (hasPart(name) && parts[name].isActive);
|
|
||||||
}
|
|
||||||
|
|
||||||
function deepExtend(dst, src) {
|
|
||||||
for (var property in src) {
|
|
||||||
if (src[property] && src[property].constructor &&
|
|
||||||
src[property].constructor === Object) {
|
|
||||||
dst[property] = dst[property] || {};
|
|
||||||
deepExtend(dst[property], src[property]);
|
|
||||||
} else {
|
|
||||||
dst[property] = src[property];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPrioritizedParts() {
|
|
||||||
var prioritizedParts = [];
|
|
||||||
for (var part in parts) {
|
|
||||||
if (parts[part].isActive) {
|
|
||||||
prioritizedParts.push(parts[part]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prioritizedParts.sort(function (a, b) {
|
|
||||||
return a.priority - b.priority;
|
|
||||||
});
|
|
||||||
return prioritizedParts;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translatePartialLoaderProvider#addPart
|
|
||||||
* @methodOf pascalprecht.translate.$translatePartialLoaderProvider
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Registers a new part of the translation table to be loaded once the
|
|
||||||
* `angular-translate` gets into runtime phase. It does not actually load any
|
|
||||||
* translation data, but only registers a part to be loaded in the future.
|
|
||||||
*
|
|
||||||
* @param {string} name A name of the part to add
|
|
||||||
* @param {int} [priority=0] Sets the load priority of this part.
|
|
||||||
* @param {string|function} urlTemplate Either a string containing an url pattern (with
|
|
||||||
* '{part}' and '{lang}') or a function(part, lang)
|
|
||||||
* returning a string.
|
|
||||||
*
|
|
||||||
* @returns {object} $translatePartialLoaderProvider, so this method is chainable
|
|
||||||
* @throws {TypeError} The method could throw a **TypeError** if you pass the param
|
|
||||||
* of the wrong type. Please, note that the `name` param has to be a
|
|
||||||
* non-empty **string**.
|
|
||||||
*/
|
|
||||||
this.addPart = function (name, priority, urlTemplate) {
|
|
||||||
if (!isStringValid(name)) {
|
|
||||||
throw new TypeError('Couldn\'t add part, part name has to be a string!');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasPart(name)) {
|
|
||||||
parts[name] = new Part(name, priority, urlTemplate);
|
|
||||||
}
|
|
||||||
parts[name].isActive = true;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdocs function
|
|
||||||
* @name pascalprecht.translate.$translatePartialLoaderProvider#setPart
|
|
||||||
* @methodOf pascalprecht.translate.$translatePartialLoaderProvider
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Sets a translation table to the specified part. This method does not make the
|
|
||||||
* specified part available, but only avoids loading this part from the server.
|
|
||||||
*
|
|
||||||
* @param {string} lang A language of the given translation table
|
|
||||||
* @param {string} part A name of the target part
|
|
||||||
* @param {object} table A translation table to set to the specified part
|
|
||||||
*
|
|
||||||
* @return {object} $translatePartialLoaderProvider, so this method is chainable
|
|
||||||
* @throws {TypeError} The method could throw a **TypeError** if you pass params
|
|
||||||
* of the wrong type. Please, note that the `lang` and `part` params have to be a
|
|
||||||
* non-empty **string**s and the `table` param has to be an object.
|
|
||||||
*/
|
|
||||||
this.setPart = function (lang, part, table) {
|
|
||||||
if (!isStringValid(lang)) {
|
|
||||||
throw new TypeError('Couldn\'t set part.`lang` parameter has to be a string!');
|
|
||||||
}
|
|
||||||
if (!isStringValid(part)) {
|
|
||||||
throw new TypeError('Couldn\'t set part.`part` parameter has to be a string!');
|
|
||||||
}
|
|
||||||
if (typeof table !== 'object' || table === null) {
|
|
||||||
throw new TypeError('Couldn\'t set part. `table` parameter has to be an object!');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasPart(part)) {
|
|
||||||
parts[part] = new Part(part);
|
|
||||||
parts[part].isActive = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
parts[part].tables[lang] = table;
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translatePartialLoaderProvider#deletePart
|
|
||||||
* @methodOf pascalprecht.translate.$translatePartialLoaderProvider
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Removes the previously added part of the translation data. So, `angular-translate` will not
|
|
||||||
* load it at the startup.
|
|
||||||
*
|
|
||||||
* @param {string} name A name of the part to delete
|
|
||||||
*
|
|
||||||
* @returns {object} $translatePartialLoaderProvider, so this method is chainable
|
|
||||||
*
|
|
||||||
* @throws {TypeError} The method could throw a **TypeError** if you pass the param of the wrong
|
|
||||||
* type. Please, note that the `name` param has to be a non-empty **string**.
|
|
||||||
*/
|
|
||||||
this.deletePart = function (name) {
|
|
||||||
if (!isStringValid(name)) {
|
|
||||||
throw new TypeError('Couldn\'t delete part, first arg has to be string.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasPart(name)) {
|
|
||||||
parts[name].isActive = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translatePartialLoaderProvider#isPartAvailable
|
|
||||||
* @methodOf pascalprecht.translate.$translatePartialLoaderProvider
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Checks if the specific part is available. A part becomes available after it was added by the
|
|
||||||
* `addPart` method. Available parts would be loaded from the server once the `angular-translate`
|
|
||||||
* asks the loader to that.
|
|
||||||
*
|
|
||||||
* @param {string} name A name of the part to check
|
|
||||||
*
|
|
||||||
* @returns {boolean} Returns **true** if the part is available now and **false** if not.
|
|
||||||
*
|
|
||||||
* @throws {TypeError} The method could throw a **TypeError** if you pass the param of the wrong
|
|
||||||
* type. Please, note that the `name` param has to be a non-empty **string**.
|
|
||||||
*/
|
|
||||||
this.isPartAvailable = isPartAvailable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc object
|
|
||||||
* @name pascalprecht.translate.$translatePartialLoader
|
|
||||||
*
|
|
||||||
* @requires $q
|
|
||||||
* @requires $http
|
|
||||||
* @requires $injector
|
|
||||||
* @requires $rootScope
|
|
||||||
* @requires $translate
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
*
|
|
||||||
* @param {object} options Options object
|
|
||||||
*
|
|
||||||
* @throws {TypeError}
|
|
||||||
*/
|
|
||||||
this.$get = ['$rootScope', '$injector', '$q', '$http', '$log',
|
|
||||||
function ($rootScope, $injector, $q, $http, $log) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc event
|
|
||||||
* @name pascalprecht.translate.$translatePartialLoader#$translatePartialLoaderStructureChanged
|
|
||||||
* @eventOf pascalprecht.translate.$translatePartialLoader
|
|
||||||
* @eventType broadcast on root scope
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* A $translatePartialLoaderStructureChanged event is called when a state of the loader was
|
|
||||||
* changed somehow. It could mean either some part is added or some part is deleted. Anyway when
|
|
||||||
* you get this event the translation table is not longer current and has to be updated.
|
|
||||||
*
|
|
||||||
* @param {string} name A name of the part which is a reason why the event was fired
|
|
||||||
*/
|
|
||||||
|
|
||||||
var service = function (options) {
|
|
||||||
if (!isStringValid(options.key)) {
|
|
||||||
throw new TypeError('Unable to load data, a key is not a non-empty string.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isStringValid(options.urlTemplate) && !angular.isFunction(options.urlTemplate)) {
|
|
||||||
throw new TypeError('Unable to load data, a urlTemplate is not a non-empty string or not a function.');
|
|
||||||
}
|
|
||||||
|
|
||||||
var errorHandler = options.loadFailureHandler;
|
|
||||||
if (errorHandler !== undefined) {
|
|
||||||
if (!angular.isString(errorHandler)) {
|
|
||||||
throw new Error('Unable to load data, a loadFailureHandler is not a string.');
|
|
||||||
} else {
|
|
||||||
errorHandler = $injector.get(errorHandler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var loaders = [],
|
|
||||||
prioritizedParts = getPrioritizedParts();
|
|
||||||
|
|
||||||
angular.forEach(prioritizedParts, function (part) {
|
|
||||||
loaders.push(
|
|
||||||
part.getTable(options.key, $q, $http, options.$http, options.urlTemplate, errorHandler)
|
|
||||||
);
|
|
||||||
part.urlTemplate = part.urlTemplate || options.urlTemplate;
|
|
||||||
});
|
|
||||||
|
|
||||||
// workaround for #1781
|
|
||||||
var structureHasBeenChangedWhileLoading = false;
|
|
||||||
var dirtyCheckEventCloser = $rootScope.$on('$translatePartialLoaderStructureChanged', function () {
|
|
||||||
structureHasBeenChangedWhileLoading = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
return $q.all(loaders)
|
|
||||||
.then(function () {
|
|
||||||
dirtyCheckEventCloser();
|
|
||||||
if (structureHasBeenChangedWhileLoading) {
|
|
||||||
if (!options.__retries) {
|
|
||||||
// the part structure has been changed while loading (the origin ones)
|
|
||||||
// this can happen if an addPart/removePart has been invoked right after a $translate.use(lang)
|
|
||||||
// TODO maybe we can optimize this with the actual list of missing parts
|
|
||||||
options.__retries = (options.__retries || 0) + 1;
|
|
||||||
return service(options);
|
|
||||||
} else {
|
|
||||||
// the part structure has been changed again while loading (retried one)
|
|
||||||
// because this could an infinite loop, this will not load another one again
|
|
||||||
$log.warn('The partial loader has detected a multiple structure change (with addPort/removePart) ' +
|
|
||||||
'while loading translations. You should consider using promises of $translate.use(lang) and ' +
|
|
||||||
'$translate.refresh(). Also parts should be added/removed right before an explicit refresh ' +
|
|
||||||
'if possible.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var table = {};
|
|
||||||
prioritizedParts = getPrioritizedParts();
|
|
||||||
angular.forEach(prioritizedParts, function (part) {
|
|
||||||
deepExtend(table, part.tables[options.key]);
|
|
||||||
});
|
|
||||||
return table;
|
|
||||||
}, function () {
|
|
||||||
dirtyCheckEventCloser();
|
|
||||||
return $q.reject(options.key);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translatePartialLoader#addPart
|
|
||||||
* @methodOf pascalprecht.translate.$translatePartialLoader
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Registers a new part of the translation table. This method does not actually perform any xhr
|
|
||||||
* requests to get translation data. The new parts will be loaded in order of priority from the server next time
|
|
||||||
* `angular-translate` asks the loader to load translations.
|
|
||||||
*
|
|
||||||
* @param {string} name A name of the part to add
|
|
||||||
* @param {int} [priority=0] Sets the load priority of this part.
|
|
||||||
*
|
|
||||||
* @returns {object} $translatePartialLoader, so this method is chainable
|
|
||||||
*
|
|
||||||
* @fires {$translatePartialLoaderStructureChanged} The $translatePartialLoaderStructureChanged
|
|
||||||
* event would be fired by this method in case the new part affected somehow on the loaders
|
|
||||||
* state. This way it means that there are a new translation data available to be loaded from
|
|
||||||
* the server.
|
|
||||||
*
|
|
||||||
* @throws {TypeError} The method could throw a **TypeError** if you pass the param of the wrong
|
|
||||||
* type. Please, note that the `name` param has to be a non-empty **string**.
|
|
||||||
*/
|
|
||||||
service.addPart = function (name, priority, urlTemplate) {
|
|
||||||
if (!isStringValid(name)) {
|
|
||||||
throw new TypeError('Couldn\'t add part, first arg has to be a string');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasPart(name)) {
|
|
||||||
parts[name] = new Part(name, priority, urlTemplate);
|
|
||||||
$rootScope.$emit('$translatePartialLoaderStructureChanged', name);
|
|
||||||
} else if (!parts[name].isActive) {
|
|
||||||
parts[name].isActive = true;
|
|
||||||
$rootScope.$emit('$translatePartialLoaderStructureChanged', name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return service;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translatePartialLoader#deletePart
|
|
||||||
* @methodOf pascalprecht.translate.$translatePartialLoader
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Deletes the previously added part of the translation data. The target part could be deleted
|
|
||||||
* either logically or physically. When the data is deleted logically it is not actually deleted
|
|
||||||
* from the browser, but the loader marks it as not active and prevents it from affecting on the
|
|
||||||
* translations. If the deleted in such way part is added again, the loader will use the
|
|
||||||
* previously loaded data rather than loading it from the server once more time. But if the data
|
|
||||||
* is deleted physically, the loader will completely remove all information about it. So in case
|
|
||||||
* of recycling this part will be loaded from the server again.
|
|
||||||
*
|
|
||||||
* @param {string} name A name of the part to delete
|
|
||||||
* @param {boolean=} [removeData=false] An indicator if the loader has to remove a loaded
|
|
||||||
* translation data physically. If the `removeData` if set to **false** the loaded data will not be
|
|
||||||
* deleted physically and might be reused in the future to prevent an additional xhr requests.
|
|
||||||
*
|
|
||||||
* @returns {object} $translatePartialLoader, so this method is chainable
|
|
||||||
*
|
|
||||||
* @fires {$translatePartialLoaderStructureChanged} The $translatePartialLoaderStructureChanged
|
|
||||||
* event would be fired by this method in case a part deletion process affects somehow on the
|
|
||||||
* loaders state. This way it means that some part of the translation data is now deprecated and
|
|
||||||
* the translation table has to be recompiled with the remaining translation parts.
|
|
||||||
*
|
|
||||||
* @throws {TypeError} The method could throw a **TypeError** if you pass some param of the
|
|
||||||
* wrong type. Please, note that the `name` param has to be a non-empty **string** and
|
|
||||||
* the `removeData` param has to be either **undefined** or **boolean**.
|
|
||||||
*/
|
|
||||||
service.deletePart = function (name, removeData) {
|
|
||||||
if (!isStringValid(name)) {
|
|
||||||
throw new TypeError('Couldn\'t delete part, first arg has to be string');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (removeData === undefined) {
|
|
||||||
removeData = false;
|
|
||||||
} else if (typeof removeData !== 'boolean') {
|
|
||||||
throw new TypeError('Invalid type of a second argument, a boolean expected.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasPart(name)) {
|
|
||||||
var wasActive = parts[name].isActive;
|
|
||||||
if (removeData) {
|
|
||||||
var $translate = $injector.get('$translate');
|
|
||||||
var cache = $translate.loaderCache();
|
|
||||||
if (typeof(cache) === 'string') {
|
|
||||||
// getting on-demand instance of loader
|
|
||||||
cache = $injector.get(cache);
|
|
||||||
}
|
|
||||||
// Purging items from cache...
|
|
||||||
if (typeof(cache) === 'object') {
|
|
||||||
angular.forEach(parts[name].tables, function (value, key) {
|
|
||||||
cache.remove(parts[name].parseUrl(parts[name].urlTemplate, key));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
delete parts[name];
|
|
||||||
} else {
|
|
||||||
parts[name].isActive = false;
|
|
||||||
}
|
|
||||||
if (wasActive) {
|
|
||||||
$rootScope.$emit('$translatePartialLoaderStructureChanged', name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return service;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translatePartialLoader#isPartLoaded
|
|
||||||
* @methodOf pascalprecht.translate.$translatePartialLoader
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Checks if the registered translation part is loaded into the translation table.
|
|
||||||
*
|
|
||||||
* @param {string} name A name of the part
|
|
||||||
* @param {string} lang A key of the language
|
|
||||||
*
|
|
||||||
* @returns {boolean} Returns **true** if the translation of the part is loaded to the translation table and **false** if not.
|
|
||||||
*
|
|
||||||
* @throws {TypeError} The method could throw a **TypeError** if you pass the param of the wrong
|
|
||||||
* type. Please, note that the `name` and `lang` params have to be non-empty **string**.
|
|
||||||
*/
|
|
||||||
service.isPartLoaded = function (name, lang) {
|
|
||||||
return angular.isDefined(parts[name]) && angular.isDefined(parts[name].tables[lang]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translatePartialLoader#getRegisteredParts
|
|
||||||
* @methodOf pascalprecht.translate.$translatePartialLoader
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Gets names of the parts that were added with the `addPart`.
|
|
||||||
*
|
|
||||||
* @returns {array} Returns array of registered parts, if none were registered then an empty array is returned.
|
|
||||||
*/
|
|
||||||
service.getRegisteredParts = function () {
|
|
||||||
var registeredParts = [];
|
|
||||||
angular.forEach(parts, function (p) {
|
|
||||||
if (p.isActive) {
|
|
||||||
registeredParts.push(p.name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return registeredParts;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translatePartialLoader#isPartAvailable
|
|
||||||
* @methodOf pascalprecht.translate.$translatePartialLoader
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Checks if a target translation part is available. The part becomes available just after it was
|
|
||||||
* added by the `addPart` method. Part's availability does not mean that it was loaded from the
|
|
||||||
* server, but only that it was added to the loader. The available part might be loaded next
|
|
||||||
* time the loader is called.
|
|
||||||
*
|
|
||||||
* @param {string} name A name of the part to delete
|
|
||||||
*
|
|
||||||
* @returns {boolean} Returns **true** if the part is available now and **false** if not.
|
|
||||||
*
|
|
||||||
* @throws {TypeError} The method could throw a **TypeError** if you pass the param of the wrong
|
|
||||||
* type. Please, note that the `name` param has to be a non-empty **string**.
|
|
||||||
*/
|
|
||||||
service.isPartAvailable = isPartAvailable;
|
|
||||||
|
|
||||||
return service;
|
|
||||||
|
|
||||||
}];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$translatePartialLoader.displayName = '$translatePartialLoader';
|
|
||||||
return 'pascalprecht.translate';
|
|
||||||
|
|
||||||
}));
|
|
|
@ -1,6 +0,0 @@
|
||||||
/*!
|
|
||||||
* angular-translate - v2.18.2 - 2020-01-04
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
|
|
||||||
*/
|
|
||||||
!function(t,e){"function"==typeof define&&define.amd?define([],function(){return e()}):"object"==typeof module&&module.exports?module.exports=e():e()}(0,function(){function t(){"use strict";function a(t,e,r){this.name=t,this.isActive=!0,this.tables={},this.priority=e||0,this.langPromises={},this.urlTemplate=r}a.prototype.parseUrl=function(t,e){return angular.isFunction(t)?t(this.name,e):t.replace(/\{part\}/g,this.name).replace(/\{lang\}/g,e)},a.prototype.getTable=function(e,t,r,a,n,i){var o=this,s=this.langPromises[e],l=t.defer(),u=function(t){o.tables[e]=t,l.resolve(t)},c=function(){l.reject(o.name)},p=function(){r(angular.extend({method:"GET",url:o.parseUrl(o.urlTemplate||n,e)},a)).then(function(t){u(t.data)},function(t){i?i(o.name,e,t).then(u,c):c()})};return this.tables[e]?l.resolve(this.tables[e]):(s?s.then(l.resolve,p):p(),this.langPromises[e]=l.promise),l.promise};var n={};function i(t){return Object.prototype.hasOwnProperty.call(n,t)}function f(t){return angular.isString(t)&&""!==t}function t(t){if(!f(t))throw new TypeError("Invalid type of a first argument, a non-empty string expected.");return i(t)&&n[t].isActive}function d(){var t=[];for(var e in n)n[e].isActive&&t.push(n[e]);return t.sort(function(t,e){return t.priority-e.priority}),t}this.addPart=function(t,e,r){if(!f(t))throw new TypeError("Couldn't add part, part name has to be a string!");return i(t)||(n[t]=new a(t,e,r)),n[t].isActive=!0,this},this.setPart=function(t,e,r){if(!f(t))throw new TypeError("Couldn't set part.`lang` parameter has to be a string!");if(!f(e))throw new TypeError("Couldn't set part.`part` parameter has to be a string!");if("object"!=typeof r||null===r)throw new TypeError("Couldn't set part. `table` parameter has to be an object!");return i(e)||(n[e]=new a(e),n[e].isActive=!1),n[e].tables[t]=r,this},this.deletePart=function(t){if(!f(t))throw new TypeError("Couldn't delete part, first arg has to be string.");return i(t)&&(n[t].isActive=!1),this},this.isPartAvailable=t,this.$get=["$rootScope","$injector","$q","$http","$log",function(o,s,l,u,c){var p=function(r){if(!f(r.key))throw new TypeError("Unable to load data, a key is not a non-empty string.");if(!f(r.urlTemplate)&&!angular.isFunction(r.urlTemplate))throw new TypeError("Unable to load data, a urlTemplate is not a non-empty string or not a function.");var e=r.loadFailureHandler;if(void 0!==e){if(!angular.isString(e))throw new Error("Unable to load data, a loadFailureHandler is not a string.");e=s.get(e)}var a=[],t=d();angular.forEach(t,function(t){a.push(t.getTable(r.key,l,u,r.$http,r.urlTemplate,e)),t.urlTemplate=t.urlTemplate||r.urlTemplate});var n=!1,i=o.$on("$translatePartialLoaderStructureChanged",function(){n=!0});return l.all(a).then(function(){if(i(),n){if(!r.__retries)return r.__retries=(r.__retries||0)+1,p(r);c.warn("The partial loader has detected a multiple structure change (with addPort/removePart) while loading translations. You should consider using promises of $translate.use(lang) and $translate.refresh(). Also parts should be added/removed right before an explicit refresh if possible.")}var e={};return t=d(),angular.forEach(t,function(t){!function t(e,r){for(var a in r)r[a]&&r[a].constructor&&r[a].constructor===Object?(e[a]=e[a]||{},t(e[a],r[a])):e[a]=r[a];return e}(e,t.tables[r.key])}),e},function(){return i(),l.reject(r.key)})};return p.addPart=function(t,e,r){if(!f(t))throw new TypeError("Couldn't add part, first arg has to be a string");return i(t)?n[t].isActive||(n[t].isActive=!0,o.$emit("$translatePartialLoaderStructureChanged",t)):(n[t]=new a(t,e,r),o.$emit("$translatePartialLoaderStructureChanged",t)),p},p.deletePart=function(r,t){if(!f(r))throw new TypeError("Couldn't delete part, first arg has to be string");if(void 0===t)t=!1;else if("boolean"!=typeof t)throw new TypeError("Invalid type of a second argument, a boolean expected.");if(i(r)){var e=n[r].isActive;if(t){var a=s.get("$translate").loaderCache();"string"==typeof a&&(a=s.get(a)),"object"==typeof a&&angular.forEach(n[r].tables,function(t,e){a.remove(n[r].parseUrl(n[r].urlTemplate,e))}),delete n[r]}else n[r].isActive=!1;e&&o.$emit("$translatePartialLoaderStructureChanged",r)}return p},p.isPartLoaded=function(t,e){return angular.isDefined(n[t])&&angular.isDefined(n[t].tables[e])},p.getRegisteredParts=function(){var e=[];return angular.forEach(n,function(t){t.isActive&&e.push(t.name)}),e},p.isPartAvailable=t,p}]}return angular.module("pascalprecht.translate").provider("$translatePartialLoader",t),t.displayName="$translatePartialLoader","pascalprecht.translate"});
|
|
|
@ -1,112 +0,0 @@
|
||||||
/*!
|
|
||||||
* angular-translate - v2.18.2 - 2020-01-04
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
|
|
||||||
*/
|
|
||||||
(function (root, factory) {
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
// AMD. Register as an anonymous module unless amdModuleId is set
|
|
||||||
define([], function () {
|
|
||||||
return (factory());
|
|
||||||
});
|
|
||||||
} else if (typeof module === 'object' && module.exports) {
|
|
||||||
// Node. Does not work with strict CommonJS, but
|
|
||||||
// only CommonJS-like environments that support module.exports,
|
|
||||||
// like Node.
|
|
||||||
module.exports = factory();
|
|
||||||
} else {
|
|
||||||
factory();
|
|
||||||
}
|
|
||||||
}(this, function () {
|
|
||||||
|
|
||||||
$translateStaticFilesLoader.$inject = ['$q', '$http'];
|
|
||||||
angular.module('pascalprecht.translate')
|
|
||||||
/**
|
|
||||||
* @ngdoc object
|
|
||||||
* @name pascalprecht.translate.$translateStaticFilesLoader
|
|
||||||
* @requires $q
|
|
||||||
* @requires $http
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Creates a loading function for a typical static file url pattern:
|
|
||||||
* "lang-en_US.json", "lang-de_DE.json", etc. Using this builder,
|
|
||||||
* the response of these urls must be an object of key-value pairs.
|
|
||||||
*
|
|
||||||
* @param {object} options Options object, which gets prefix, suffix, key, and fileMap
|
|
||||||
*/
|
|
||||||
.factory('$translateStaticFilesLoader', $translateStaticFilesLoader);
|
|
||||||
|
|
||||||
function $translateStaticFilesLoader($q, $http) {
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
return function (options) {
|
|
||||||
|
|
||||||
if (!options || (!angular.isArray(options.files) && (!angular.isString(options.prefix) || !angular.isString(options.suffix)))) {
|
|
||||||
throw new Error('Couldn\'t load static files, no files and prefix or suffix specified!');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!options.files) {
|
|
||||||
options.files = [{
|
|
||||||
prefix: options.prefix,
|
|
||||||
suffix: options.suffix
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
var load = function (file) {
|
|
||||||
if (!file || (!angular.isString(file.prefix) || !angular.isString(file.suffix))) {
|
|
||||||
throw new Error('Couldn\'t load static file, no prefix or suffix specified!');
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileUrl = [
|
|
||||||
file.prefix,
|
|
||||||
options.key,
|
|
||||||
file.suffix
|
|
||||||
].join('');
|
|
||||||
|
|
||||||
if (angular.isObject(options.fileMap) && options.fileMap[fileUrl]) {
|
|
||||||
fileUrl = options.fileMap[fileUrl];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $http(angular.extend({
|
|
||||||
url: fileUrl,
|
|
||||||
method: 'GET'
|
|
||||||
}, options.$http))
|
|
||||||
.then(function(result) {
|
|
||||||
return result.data;
|
|
||||||
}, function () {
|
|
||||||
return $q.reject(options.key);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var promises = [],
|
|
||||||
length = options.files.length;
|
|
||||||
|
|
||||||
for (var i = 0; i < length; i++) {
|
|
||||||
promises.push(load({
|
|
||||||
prefix: options.files[i].prefix,
|
|
||||||
key: options.key,
|
|
||||||
suffix: options.files[i].suffix
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $q.all(promises)
|
|
||||||
.then(function (data) {
|
|
||||||
var length = data.length,
|
|
||||||
mergedData = {};
|
|
||||||
|
|
||||||
for (var i = 0; i < length; i++) {
|
|
||||||
for (var key in data[i]) {
|
|
||||||
mergedData[key] = data[i][key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mergedData;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
$translateStaticFilesLoader.displayName = '$translateStaticFilesLoader';
|
|
||||||
return 'pascalprecht.translate';
|
|
||||||
|
|
||||||
}));
|
|
|
@ -1,6 +0,0 @@
|
||||||
/*!
|
|
||||||
* angular-translate - v2.18.2 - 2020-01-04
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
|
|
||||||
*/
|
|
||||||
!function(e,i){"function"==typeof define&&define.amd?define([],function(){return i()}):"object"==typeof module&&module.exports?module.exports=i():i()}(0,function(){function e(n,a){"use strict";return function(r){if(!(r&&(angular.isArray(r.files)||angular.isString(r.prefix)&&angular.isString(r.suffix))))throw new Error("Couldn't load static files, no files and prefix or suffix specified!");r.files||(r.files=[{prefix:r.prefix,suffix:r.suffix}]);for(var e=function(e){if(!e||!angular.isString(e.prefix)||!angular.isString(e.suffix))throw new Error("Couldn't load static file, no prefix or suffix specified!");var i=[e.prefix,r.key,e.suffix].join("");return angular.isObject(r.fileMap)&&r.fileMap[i]&&(i=r.fileMap[i]),a(angular.extend({url:i,method:"GET"},r.$http)).then(function(e){return e.data},function(){return n.reject(r.key)})},i=[],t=r.files.length,f=0;f<t;f++)i.push(e({prefix:r.files[f].prefix,key:r.key,suffix:r.files[f].suffix}));return n.all(i).then(function(e){for(var i=e.length,r={},t=0;t<i;t++)for(var f in e[t])r[f]=e[t][f];return r})}}return e.$inject=["$q","$http"],angular.module("pascalprecht.translate").factory("$translateStaticFilesLoader",e),e.displayName="$translateStaticFilesLoader","pascalprecht.translate"});
|
|
|
@ -1,73 +0,0 @@
|
||||||
/*!
|
|
||||||
* angular-translate - v2.18.2 - 2020-01-04
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
|
|
||||||
*/
|
|
||||||
(function (root, factory) {
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
// AMD. Register as an anonymous module unless amdModuleId is set
|
|
||||||
define([], function () {
|
|
||||||
return (factory());
|
|
||||||
});
|
|
||||||
} else if (typeof module === 'object' && module.exports) {
|
|
||||||
// Node. Does not work with strict CommonJS, but
|
|
||||||
// only CommonJS-like environments that support module.exports,
|
|
||||||
// like Node.
|
|
||||||
module.exports = factory();
|
|
||||||
} else {
|
|
||||||
factory();
|
|
||||||
}
|
|
||||||
}(this, function () {
|
|
||||||
|
|
||||||
$translateUrlLoader.$inject = ['$q', '$http'];
|
|
||||||
angular.module('pascalprecht.translate')
|
|
||||||
/**
|
|
||||||
* @ngdoc object
|
|
||||||
* @name pascalprecht.translate.$translateUrlLoader
|
|
||||||
* @requires $q
|
|
||||||
* @requires $http
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Creates a loading function for a typical dynamic url pattern:
|
|
||||||
* "locale.php?lang=en_US", "locale.php?lang=de_DE", "locale.php?language=nl_NL" etc.
|
|
||||||
* Prefixing the specified url, the current requested, language id will be applied
|
|
||||||
* with "?{queryParameter}={key}".
|
|
||||||
* Using this service, the response of these urls must be an object of
|
|
||||||
* key-value pairs.
|
|
||||||
*
|
|
||||||
* @param {object} options Options object, which gets the url, key and
|
|
||||||
* optional queryParameter ('lang' is used by default).
|
|
||||||
*/
|
|
||||||
.factory('$translateUrlLoader', $translateUrlLoader);
|
|
||||||
|
|
||||||
function $translateUrlLoader($q, $http) {
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
return function (options) {
|
|
||||||
|
|
||||||
if (!options || !options.url) {
|
|
||||||
throw new Error('Couldn\'t use urlLoader since no url is given!');
|
|
||||||
}
|
|
||||||
|
|
||||||
var requestParams = {};
|
|
||||||
|
|
||||||
requestParams[options.queryParameter || 'lang'] = options.key;
|
|
||||||
|
|
||||||
return $http(angular.extend({
|
|
||||||
url: options.url,
|
|
||||||
params: requestParams,
|
|
||||||
method: 'GET'
|
|
||||||
}, options.$http))
|
|
||||||
.then(function(result) {
|
|
||||||
return result.data;
|
|
||||||
}, function () {
|
|
||||||
return $q.reject(options.key);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
$translateUrlLoader.displayName = '$translateUrlLoader';
|
|
||||||
return 'pascalprecht.translate';
|
|
||||||
|
|
||||||
}));
|
|
|
@ -1,6 +0,0 @@
|
||||||
/*!
|
|
||||||
* angular-translate - v2.18.2 - 2020-01-04
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
|
|
||||||
*/
|
|
||||||
!function(e,t){"function"==typeof define&&define.amd?define([],function(){return t()}):"object"==typeof module&&module.exports?module.exports=t():t()}(0,function(){function e(r,n){"use strict";return function(e){if(!e||!e.url)throw new Error("Couldn't use urlLoader since no url is given!");var t={};return t[e.queryParameter||"lang"]=e.key,n(angular.extend({url:e.url,params:t,method:"GET"},e.$http)).then(function(e){return e.data},function(){return r.reject(e.key)})}}return e.$inject=["$q","$http"],angular.module("pascalprecht.translate").factory("$translateUrlLoader",e),e.displayName="$translateUrlLoader","pascalprecht.translate"});
|
|
|
@ -1,121 +0,0 @@
|
||||||
/*!
|
|
||||||
* angular-translate - v2.18.2 - 2020-01-04
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
|
|
||||||
*/
|
|
||||||
(function (root, factory) {
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
// AMD. Register as an anonymous module unless amdModuleId is set
|
|
||||||
define([], function () {
|
|
||||||
return (factory());
|
|
||||||
});
|
|
||||||
} else if (typeof module === 'object' && module.exports) {
|
|
||||||
// Node. Does not work with strict CommonJS, but
|
|
||||||
// only CommonJS-like environments that support module.exports,
|
|
||||||
// like Node.
|
|
||||||
module.exports = factory();
|
|
||||||
} else {
|
|
||||||
factory();
|
|
||||||
}
|
|
||||||
}(this, function () {
|
|
||||||
|
|
||||||
$translateCookieStorageFactory.$inject = ['$injector'];
|
|
||||||
angular.module('pascalprecht.translate')
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc object
|
|
||||||
* @name pascalprecht.translate.$translateCookieStorage
|
|
||||||
* @requires $cookieStore
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Abstraction layer for cookieStore. This service is used when telling angular-translate
|
|
||||||
* to use cookieStore as storage.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
.factory('$translateCookieStorage', $translateCookieStorageFactory);
|
|
||||||
|
|
||||||
function $translateCookieStorageFactory($injector) {
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
// Since AngularJS 1.4, $cookieStore is deprecated
|
|
||||||
var delegate;
|
|
||||||
if (angular.version.major === 1 && angular.version.minor >= 4) {
|
|
||||||
var $cookies = $injector.get('$cookies');
|
|
||||||
delegate = {
|
|
||||||
get : function (key) {
|
|
||||||
return $cookies.get(key);
|
|
||||||
},
|
|
||||||
put : function (key, value) {
|
|
||||||
$cookies.put(key, value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
var $cookieStore = $injector.get('$cookieStore');
|
|
||||||
delegate = {
|
|
||||||
get : function (key) {
|
|
||||||
return $cookieStore.get(key);
|
|
||||||
},
|
|
||||||
put : function (key, value) {
|
|
||||||
$cookieStore.put(key, value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var $translateCookieStorage = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translateCookieStorage#get
|
|
||||||
* @methodOf pascalprecht.translate.$translateCookieStorage
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Returns an item from cookieStorage by given name.
|
|
||||||
*
|
|
||||||
* @param {string} name Item name
|
|
||||||
* @return {string} Value of item name
|
|
||||||
*/
|
|
||||||
get : function (name) {
|
|
||||||
return delegate.get(name);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translateCookieStorage#set
|
|
||||||
* @methodOf pascalprecht.translate.$translateCookieStorage
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Sets an item in cookieStorage by given name.
|
|
||||||
*
|
|
||||||
* @deprecated use #put
|
|
||||||
*
|
|
||||||
* @param {string} name Item name
|
|
||||||
* @param {string} value Item value
|
|
||||||
*/
|
|
||||||
set : function (name, value) {
|
|
||||||
delegate.put(name, value);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translateCookieStorage#put
|
|
||||||
* @methodOf pascalprecht.translate.$translateCookieStorage
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Sets an item in cookieStorage by given name.
|
|
||||||
*
|
|
||||||
* @param {string} name Item name
|
|
||||||
* @param {string} value Item value
|
|
||||||
*/
|
|
||||||
put : function (name, value) {
|
|
||||||
delegate.put(name, value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return $translateCookieStorage;
|
|
||||||
}
|
|
||||||
|
|
||||||
$translateCookieStorageFactory.displayName = '$translateCookieStorage';
|
|
||||||
return 'pascalprecht.translate';
|
|
||||||
|
|
||||||
}));
|
|
|
@ -1,6 +0,0 @@
|
||||||
/*!
|
|
||||||
* angular-translate - v2.18.2 - 2020-01-04
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
|
|
||||||
*/
|
|
||||||
!function(t,e){"function"==typeof define&&define.amd?define([],function(){return e()}):"object"==typeof module&&module.exports?module.exports=e():e()}(0,function(){function t(t){"use strict";var n;if(1===angular.version.major&&4<=angular.version.minor){var o=t.get("$cookies");n={get:function(t){return o.get(t)},put:function(t,e){o.put(t,e)}}}else{var r=t.get("$cookieStore");n={get:function(t){return r.get(t)},put:function(t,e){r.put(t,e)}}}return{get:function(t){return n.get(t)},set:function(t,e){n.put(t,e)},put:function(t,e){n.put(t,e)}}}return t.$inject=["$injector"],angular.module("pascalprecht.translate").factory("$translateCookieStorage",t),t.displayName="$translateCookieStorage","pascalprecht.translate"});
|
|
|
@ -1,123 +0,0 @@
|
||||||
/*!
|
|
||||||
* angular-translate - v2.18.2 - 2020-01-04
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
|
|
||||||
*/
|
|
||||||
(function (root, factory) {
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
// AMD. Register as an anonymous module unless amdModuleId is set
|
|
||||||
define([], function () {
|
|
||||||
return (factory());
|
|
||||||
});
|
|
||||||
} else if (typeof module === 'object' && module.exports) {
|
|
||||||
// Node. Does not work with strict CommonJS, but
|
|
||||||
// only CommonJS-like environments that support module.exports,
|
|
||||||
// like Node.
|
|
||||||
module.exports = factory();
|
|
||||||
} else {
|
|
||||||
factory();
|
|
||||||
}
|
|
||||||
}(this, function () {
|
|
||||||
|
|
||||||
$translateLocalStorageFactory.$inject = ['$window', '$translateCookieStorage'];
|
|
||||||
angular.module('pascalprecht.translate')
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc object
|
|
||||||
* @name pascalprecht.translate.$translateLocalStorage
|
|
||||||
* @requires $window
|
|
||||||
* @requires $translateCookieStorage
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Abstraction layer for localStorage. This service is used when telling angular-translate
|
|
||||||
* to use localStorage as storage.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
.factory('$translateLocalStorage', $translateLocalStorageFactory);
|
|
||||||
|
|
||||||
function $translateLocalStorageFactory($window, $translateCookieStorage) {
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
// Setup adapter
|
|
||||||
var localStorageAdapter = (function(){
|
|
||||||
var langKey;
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translateLocalStorage#get
|
|
||||||
* @methodOf pascalprecht.translate.$translateLocalStorage
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Returns an item from localStorage by given name.
|
|
||||||
*
|
|
||||||
* @param {string} name Item name
|
|
||||||
* @return {string} Value of item name
|
|
||||||
*/
|
|
||||||
get: function (name) {
|
|
||||||
if(!langKey) {
|
|
||||||
langKey = $window.localStorage.getItem(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return langKey;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translateLocalStorage#set
|
|
||||||
* @methodOf pascalprecht.translate.$translateLocalStorage
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Sets an item in localStorage by given name.
|
|
||||||
*
|
|
||||||
* @deprecated use #put
|
|
||||||
*
|
|
||||||
* @param {string} name Item name
|
|
||||||
* @param {string} value Item value
|
|
||||||
*/
|
|
||||||
set: function (name, value) {
|
|
||||||
langKey=value;
|
|
||||||
$window.localStorage.setItem(name, value);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name pascalprecht.translate.$translateLocalStorage#put
|
|
||||||
* @methodOf pascalprecht.translate.$translateLocalStorage
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Sets an item in localStorage by given name.
|
|
||||||
*
|
|
||||||
* @param {string} name Item name
|
|
||||||
* @param {string} value Item value
|
|
||||||
*/
|
|
||||||
put: function (name, value) {
|
|
||||||
langKey=value;
|
|
||||||
$window.localStorage.setItem(name, value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}());
|
|
||||||
|
|
||||||
var hasLocalStorageSupport = 'localStorage' in $window;
|
|
||||||
if (hasLocalStorageSupport) {
|
|
||||||
var testKey = 'pascalprecht.translate.storageTest';
|
|
||||||
try {
|
|
||||||
// this check have to be wrapped within a try/catch because on
|
|
||||||
// a SecurityError: Dom Exception 18 on iOS
|
|
||||||
if ($window.localStorage !== null) {
|
|
||||||
$window.localStorage.setItem(testKey, 'foo');
|
|
||||||
$window.localStorage.removeItem(testKey);
|
|
||||||
hasLocalStorageSupport = true;
|
|
||||||
} else {
|
|
||||||
hasLocalStorageSupport = false;
|
|
||||||
}
|
|
||||||
} catch (e){
|
|
||||||
hasLocalStorageSupport = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var $translateLocalStorage = hasLocalStorageSupport ? localStorageAdapter : $translateCookieStorage;
|
|
||||||
return $translateLocalStorage;
|
|
||||||
}
|
|
||||||
|
|
||||||
$translateLocalStorageFactory.displayName = '$translateLocalStorageFactory';
|
|
||||||
return 'pascalprecht.translate';
|
|
||||||
|
|
||||||
}));
|
|
|
@ -1,6 +0,0 @@
|
||||||
/*!
|
|
||||||
* angular-translate - v2.18.2 - 2020-01-04
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
|
|
||||||
*/
|
|
||||||
!function(t,e){"function"==typeof define&&define.amd?define([],function(){return e()}):"object"==typeof module&&module.exports?module.exports=e():e()}(0,function(){function t(a,t){"use strict";var o,e={get:function(t){return o||(o=a.localStorage.getItem(t)),o},set:function(t,e){o=e,a.localStorage.setItem(t,e)},put:function(t,e){o=e,a.localStorage.setItem(t,e)}},r="localStorage"in a;if(r){var n="pascalprecht.translate.storageTest";try{r=null!==a.localStorage&&(a.localStorage.setItem(n,"foo"),a.localStorage.removeItem(n),!0)}catch(t){r=!1}}return r?e:t}return t.$inject=["$window","$translateCookieStorage"],angular.module("pascalprecht.translate").factory("$translateLocalStorage",t),t.displayName="$translateLocalStorageFactory","pascalprecht.translate"});
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
@ -1,137 +0,0 @@
|
||||||
{
|
|
||||||
"_from": "angular-translate@2.18.2",
|
|
||||||
"_id": "angular-translate@2.18.2",
|
|
||||||
"_inBundle": false,
|
|
||||||
"_integrity": "sha512-aAtNieh0fUv6yM6vKuWsdswT0BbOf6kvsu+QZ15Fp10rKEienMs3M8aPWyd9IVZ5pA1GaRJir6T8OvWGG4J+Fw==",
|
|
||||||
"_location": "/angular-translate",
|
|
||||||
"_phantomChildren": {},
|
|
||||||
"_requested": {
|
|
||||||
"type": "version",
|
|
||||||
"registry": true,
|
|
||||||
"raw": "angular-translate@2.18.2",
|
|
||||||
"name": "angular-translate",
|
|
||||||
"escapedName": "angular-translate",
|
|
||||||
"rawSpec": "2.18.2",
|
|
||||||
"saveSpec": null,
|
|
||||||
"fetchSpec": "2.18.2"
|
|
||||||
},
|
|
||||||
"_requiredBy": [
|
|
||||||
"/",
|
|
||||||
"/angular-translate-loader-url"
|
|
||||||
],
|
|
||||||
"_resolved": "https://registry.npmjs.org/angular-translate/-/angular-translate-2.18.2.tgz",
|
|
||||||
"_shasum": "2a26653d179f7043c0ffa66fdf65155d01c82e06",
|
|
||||||
"_spec": "angular-translate@2.18.2",
|
|
||||||
"_where": "/home/abstractj/github/keycloak/themes/src/main/resources/theme/keycloak/common/resources",
|
|
||||||
"author": {
|
|
||||||
"name": "Pascal Precht"
|
|
||||||
},
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/angular-translate/angular-translate/issues"
|
|
||||||
},
|
|
||||||
"bundleDependencies": false,
|
|
||||||
"contributors": [
|
|
||||||
{
|
|
||||||
"name": "Jan Philipp",
|
|
||||||
"email": "knallisworld@googlemail.com",
|
|
||||||
"url": "https://github.com/knalli"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Max Prichinenko"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Thorsten S"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"dependencies": {
|
|
||||||
"angular": "^1.7.9"
|
|
||||||
},
|
|
||||||
"deprecated": false,
|
|
||||||
"description": "A translation module for AngularJS",
|
|
||||||
"devDependencies": {
|
|
||||||
"adm-zip": "^0.4.13",
|
|
||||||
"body-parser": "^1.19.0",
|
|
||||||
"bower": "^1.8.8",
|
|
||||||
"errorhandler": "^1.5.1",
|
|
||||||
"express": "^4.17.1",
|
|
||||||
"express-session": "^1.17.0",
|
|
||||||
"fbjs-scripts": "^0.8.3",
|
|
||||||
"fsevents": "^1.2.11",
|
|
||||||
"grunt": "^1.0.4",
|
|
||||||
"grunt-bower-install-simple": "1.2.4",
|
|
||||||
"grunt-bump": "^0.8.0",
|
|
||||||
"grunt-cli": "^1.3.2",
|
|
||||||
"grunt-contrib-clean": "^1.0.0",
|
|
||||||
"grunt-contrib-concat": "^1.0.0",
|
|
||||||
"grunt-contrib-copy": "^1.0.0",
|
|
||||||
"grunt-contrib-jshint": "^1.0.0",
|
|
||||||
"grunt-contrib-uglify": "^3.4.0",
|
|
||||||
"grunt-contrib-watch": "^1.1.0",
|
|
||||||
"grunt-conventional-changelog": "^6.1.0",
|
|
||||||
"grunt-file-append": "0.0.7",
|
|
||||||
"grunt-karma": "^2.0.0",
|
|
||||||
"grunt-ng-annotate": "^3.0.0",
|
|
||||||
"grunt-ngdocs": "^0.2.11",
|
|
||||||
"grunt-parallel": "^0.5.1",
|
|
||||||
"grunt-umd": "^2.3.3",
|
|
||||||
"grunt-version": "^1.3.2",
|
|
||||||
"inquirer": "^3.0.1",
|
|
||||||
"jasmine-core": "^2.99.1",
|
|
||||||
"karma": "^1.3.0",
|
|
||||||
"karma-chrome-launcher": "^2.0.0",
|
|
||||||
"karma-coverage": "^1.1.2",
|
|
||||||
"karma-firefox-launcher": "~1.0.0",
|
|
||||||
"karma-jasmine": "^1.1.2",
|
|
||||||
"karma-phantomjs-launcher": "^1.0.0",
|
|
||||||
"load-grunt-tasks": "^3.4.1",
|
|
||||||
"method-override": "^2.3.7",
|
|
||||||
"morgan": "^1.9.1",
|
|
||||||
"multer": "^1.4.2",
|
|
||||||
"phantomjs-prebuilt": "^2.1.16",
|
|
||||||
"plato": "^1.5.0",
|
|
||||||
"publish-release": "^1.6.1",
|
|
||||||
"pug": "^2.0.4",
|
|
||||||
"serve-favicon": "^2.5.0",
|
|
||||||
"tar": "^4.4.13"
|
|
||||||
},
|
|
||||||
"devEngines": {
|
|
||||||
"node": ">=12.14",
|
|
||||||
"npm": ">=6.13"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/angular-translate/angular-translate#readme",
|
|
||||||
"keywords": [
|
|
||||||
"angular-translate",
|
|
||||||
"angular",
|
|
||||||
"AngularJS",
|
|
||||||
"translation"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "dist/angular-translate.js",
|
|
||||||
"name": "angular-translate",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+ssh://git@github.com/angular-translate/angular-translate.git"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "npm run-script -s check-env && grunt build",
|
|
||||||
"build-site": "npm run -s build-site-all-languages; npm run -s build-site-plato-report",
|
|
||||||
"build-site-all-languages": "./build_tools/generate_site.sh",
|
|
||||||
"build-site-by-language": "./build_tools/generate_site_by_language.sh",
|
|
||||||
"build-site-plato-report": "rm -rf ./site/plato && plato -d plato -l .jshintrc src/*.js src/**/*.js && mv plato site",
|
|
||||||
"check-env": "node node_modules/fbjs-scripts/node/check-dev-engines.js package.json",
|
|
||||||
"clean-test-scopes": "for f in test_scopes/*; do (cd $f; rm -rf bower_components); done",
|
|
||||||
"compile": "npm run-script -s check-env && grunt compile",
|
|
||||||
"lint": "grunt lint",
|
|
||||||
"prepare": "bower install",
|
|
||||||
"shipit": "npm run-script -s check-env && bower install && bower update && grunt prepare-release",
|
|
||||||
"start-demo": "node build_tools/server.js",
|
|
||||||
"test": "npm run-script -s check-env && grunt install-test && grunt test",
|
|
||||||
"test-headless": "npm run-script -s check-env && grunt test-headless",
|
|
||||||
"test-scopes": "npm run-script -s check-env && grunt install-test && for f in test_scopes/*; do TEST_SCOPE=\"`basename $f`\" grunt test; done",
|
|
||||||
"upload-github-release": "node build_tools/upload-github-release.js"
|
|
||||||
},
|
|
||||||
"version": "2.18.2"
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
|
|
||||||
# Runtime data
|
|
||||||
pids
|
|
||||||
*.pid
|
|
||||||
*.seed
|
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
|
|
||||||
# nyc test coverage
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
|
||||||
build/Release
|
|
||||||
|
|
||||||
# Dependency directories
|
|
||||||
node_modules
|
|
||||||
jspm_packages
|
|
||||||
|
|
||||||
# Optional npm cache directory
|
|
||||||
.npm
|
|
||||||
|
|
||||||
# Optional REPL history
|
|
||||||
.node_repl_history
|
|
||||||
.idea
|
|
|
@ -1,21 +0,0 @@
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2016 it-ailen
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
|
@ -1 +0,0 @@
|
||||||
# angular-treeview
|
|
|
@ -1,52 +0,0 @@
|
||||||
/**
|
|
||||||
* Created by hyku on 16/9/29.
|
|
||||||
*/
|
|
||||||
var path = require("path");
|
|
||||||
var webpack = require("webpack");
|
|
||||||
|
|
||||||
var config = {
|
|
||||||
entry: {
|
|
||||||
tree: "./src/tree.js"
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, ".."),
|
|
||||||
filename: "[name].js"
|
|
||||||
},
|
|
||||||
// resolve: {
|
|
||||||
// root: path.resolve(__dirname, "./src")
|
|
||||||
// },
|
|
||||||
module: {
|
|
||||||
loaders: [
|
|
||||||
{
|
|
||||||
test: /\.less$/i,
|
|
||||||
loaders: ["style", "css", "less"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.html$/i,
|
|
||||||
loaders: ["html"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.css$/i,
|
|
||||||
loaders: ["style", "css"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(jpe?g|png|gif|svg)$/i,
|
|
||||||
loader: "url-loader?limit=10000&name=images/[name].[ext]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(ttf|eot|woff2?)$/,
|
|
||||||
loader: 'file?name=etc/[name].[ext]'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.optimize.DedupePlugin(),
|
|
||||||
new webpack.ProvidePlugin({
|
|
||||||
$: "jquery",
|
|
||||||
jQuery: "jquery"
|
|
||||||
}),
|
|
||||||
new webpack.optimize.OccurenceOrderPlugin()
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = config;
|
|
Binary file not shown.
Before Width: | Height: | Size: 14 KiB |
|
@ -1,7 +0,0 @@
|
||||||
/**
|
|
||||||
* Created by hyku on 2016/10/13.
|
|
||||||
*/
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
require("./tree");
|
|
||||||
module.exports = "angular.tree";
|
|
|
@ -1,59 +0,0 @@
|
||||||
{
|
|
||||||
"_from": "angular-treeview@0.1.5",
|
|
||||||
"_id": "angular-treeview@0.1.5",
|
|
||||||
"_inBundle": false,
|
|
||||||
"_integrity": "sha1-7Hl9TQAbIBcsmD5l2FXrzYFStPo=",
|
|
||||||
"_location": "/angular-treeview",
|
|
||||||
"_phantomChildren": {},
|
|
||||||
"_requested": {
|
|
||||||
"type": "version",
|
|
||||||
"registry": true,
|
|
||||||
"raw": "angular-treeview@0.1.5",
|
|
||||||
"name": "angular-treeview",
|
|
||||||
"escapedName": "angular-treeview",
|
|
||||||
"rawSpec": "0.1.5",
|
|
||||||
"saveSpec": null,
|
|
||||||
"fetchSpec": "0.1.5"
|
|
||||||
},
|
|
||||||
"_requiredBy": [
|
|
||||||
"/"
|
|
||||||
],
|
|
||||||
"_resolved": "https://registry.npmjs.org/angular-treeview/-/angular-treeview-0.1.5.tgz",
|
|
||||||
"_shasum": "ec797d4d001b20172c983e65d855ebcd8152b4fa",
|
|
||||||
"_spec": "angular-treeview@0.1.5",
|
|
||||||
"_where": "/home/abstractj/github/keycloak/themes/src/main/resources/theme/keycloak/common/resources",
|
|
||||||
"author": {
|
|
||||||
"name": "Allen Zou"
|
|
||||||
},
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/it-ailen/angular-treeview/issues"
|
|
||||||
},
|
|
||||||
"bundleDependencies": false,
|
|
||||||
"deprecated": false,
|
|
||||||
"description": "Treeview with angular.",
|
|
||||||
"devDependencies": {
|
|
||||||
"css-loader": "^0.25.0",
|
|
||||||
"html-loader": "^0.4.4",
|
|
||||||
"less": "^2.7.1",
|
|
||||||
"less-loader": "^2.2.3",
|
|
||||||
"style-loader": "^0.13.1",
|
|
||||||
"url-loader": "^0.5.7",
|
|
||||||
"webpack": "^1.13.2"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/it-ailen/angular-treeview#readme",
|
|
||||||
"keywords": [
|
|
||||||
"angular",
|
|
||||||
"treeview"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "index.js",
|
|
||||||
"name": "angular-treeview",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/it-ailen/angular-treeview.git"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "webpack --config build/webpack.config.base.js"
|
|
||||||
},
|
|
||||||
"version": "0.1.5"
|
|
||||||
}
|
|
|
@ -1,164 +0,0 @@
|
||||||
/**
|
|
||||||
* Created by Allen Zou on 2016/10/13.
|
|
||||||
*/
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
require("./view/tree.less");
|
|
||||||
var fileIcon = require("./view/imgs/file.png");
|
|
||||||
var folderIcon = require("./view/imgs/folder.png");
|
|
||||||
var closedFolderIcon = require("./view/imgs/folder-closed.png");
|
|
||||||
var plusIcon = require("./view/imgs/plus.png");
|
|
||||||
var removeIcon = require("./view/imgs/remove.png");
|
|
||||||
|
|
||||||
var tree = angular.module("angular.tree", []);
|
|
||||||
tree
|
|
||||||
.directive("treeNode", function () {
|
|
||||||
return {
|
|
||||||
scope: {
|
|
||||||
item: "=",
|
|
||||||
adapter: "=",
|
|
||||||
icon: "=",
|
|
||||||
folderOpen: "=",
|
|
||||||
folderClose: "=",
|
|
||||||
nodeClick: "=",
|
|
||||||
childrenLoader: "=",
|
|
||||||
addItem: "=",
|
|
||||||
removeItem: "=",
|
|
||||||
editItem: "="
|
|
||||||
},
|
|
||||||
require: [],
|
|
||||||
restrict: "E",
|
|
||||||
// templateUrl: "directive/tree/node.html",
|
|
||||||
template: require("./view/node.html"),
|
|
||||||
link: function($scope, element, attributes, controllers) {
|
|
||||||
$scope.open = false;
|
|
||||||
$scope.add_btn = plusIcon;
|
|
||||||
$scope.remove_btn = removeIcon;
|
|
||||||
function load_children() {
|
|
||||||
if ($scope.childrenLoader) {
|
|
||||||
$scope.childrenLoader($scope.item)
|
|
||||||
.then(function(children) {
|
|
||||||
$scope.subNodes = children;
|
|
||||||
})
|
|
||||||
.catch(function(error) {
|
|
||||||
console.error(error);
|
|
||||||
$scope.subNodes = [];
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
$scope.subNodes = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$scope.wrap_node_click = function() {
|
|
||||||
if ($scope.item) {
|
|
||||||
var adaptedItem = $scope.adapter($scope.item);
|
|
||||||
if (adaptedItem.type === "branch") {
|
|
||||||
if ($scope.open) {
|
|
||||||
$scope.open = false;
|
|
||||||
$scope.folderClose && $scope.folderClose($scope.item);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$scope.open = true;
|
|
||||||
$scope.folderOpen && $scope.folderOpen($scope.item);
|
|
||||||
load_children();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$scope.nodeClick && $scope.nodeClick($scope.item);
|
|
||||||
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
$scope.resolve_icon = function() {
|
|
||||||
var icon = null;
|
|
||||||
var adaptedItem = $scope.adapter($scope.item);
|
|
||||||
if (adaptedItem.type === 'branch') {
|
|
||||||
icon = ($scope.icon && $scope.icon($scope.item, $scope.open))
|
|
||||||
|| (!$scope.open && closedFolderIcon)
|
|
||||||
|| ($scope.open && folderIcon);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
icon = ($scope.icon && $scope.icon($scope.item))
|
|
||||||
|| fileIcon;
|
|
||||||
}
|
|
||||||
return icon;
|
|
||||||
};
|
|
||||||
$scope.node_class = function() {
|
|
||||||
var classes = ["node"];
|
|
||||||
var adaptedItem = $scope.adapter($scope.item);
|
|
||||||
if (adaptedItem.type === 'branch') {
|
|
||||||
classes.push("branch");
|
|
||||||
if ($scope.open) {
|
|
||||||
classes.push("open");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
classes.push("closed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
classes.push("leaf");
|
|
||||||
}
|
|
||||||
return classes;
|
|
||||||
};
|
|
||||||
$scope.add_child = function() {
|
|
||||||
if ($scope.addItem) {
|
|
||||||
$scope.addItem($scope.item)
|
|
||||||
.then(function() {
|
|
||||||
load_children();
|
|
||||||
})
|
|
||||||
;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
$scope.remove_self = function() {
|
|
||||||
if ($scope.removeItem) {
|
|
||||||
$scope.removeItem($scope.item)
|
|
||||||
.then(function() {
|
|
||||||
load_children();
|
|
||||||
})
|
|
||||||
;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
$scope.edit = function() {
|
|
||||||
console.log("edit:::");
|
|
||||||
console.log($scope.editItem);
|
|
||||||
$scope.editItem && $scope.editItem($scope.item);
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.directive("tree", function () {
|
|
||||||
var link = function($scope, element, attributes, controllers) {
|
|
||||||
$scope.itemAdapter = $scope.adapter || function(item) {
|
|
||||||
console.log("in tree .adapter");
|
|
||||||
return item;
|
|
||||||
};
|
|
||||||
$scope.tree_class = function() {
|
|
||||||
var classes = ["tree"];
|
|
||||||
return classes;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
scope: {
|
|
||||||
root: "=root",
|
|
||||||
adapter: "=",
|
|
||||||
icon: "=",
|
|
||||||
folderOpen: "=",
|
|
||||||
folderClose: "=",
|
|
||||||
nodeClick: "=",
|
|
||||||
childrenLoader: "=",
|
|
||||||
addItem: "=",
|
|
||||||
removeItem: "=",
|
|
||||||
editItem: "="
|
|
||||||
},
|
|
||||||
require: [],
|
|
||||||
restrict: "E",
|
|
||||||
// templateUrl: "directive/tree/tree.html",
|
|
||||||
template: require("./view/tree.html"),
|
|
||||||
link: link
|
|
||||||
}
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
module.exports = tree;
|
|
Binary file not shown.
Before Width: | Height: | Size: 263 B |
Binary file not shown.
Before Width: | Height: | Size: 281 B |
Binary file not shown.
Before Width: | Height: | Size: 289 B |
Binary file not shown.
Before Width: | Height: | Size: 7.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 5.9 KiB |
|
@ -1,24 +0,0 @@
|
||||||
<div ng-class="node_class()">
|
|
||||||
<div class="directory-level" ng-click="wrap_node_click()">
|
|
||||||
<img class="icon" ng-src="{{ resolve_icon() }}">
|
|
||||||
<span>{{ adapter(item).text }}</span>
|
|
||||||
<div class="operation" ng-click="$event.stopPropagation()">
|
|
||||||
<a href class="add" ng-click="add_child()" ng-if="adapter(item).type==='branch'">
|
|
||||||
<img ng-src="{{ add_btn }}">
|
|
||||||
</a>
|
|
||||||
<a href class="remove" ng-click="remove_self()">
|
|
||||||
<img ng-src="{{ remove_btn }}">
|
|
||||||
</a>
|
|
||||||
<a href class="edit" ng-click="edit()">
|
|
||||||
<span class="glyphicon glyphicon-edit"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="sub-node" ng-if="open" ng-repeat="node in subNodes">
|
|
||||||
<tree-node item="node" adapter="adapter" icon="icon"
|
|
||||||
folder-open="folderOpen" folder-close="folderClose"
|
|
||||||
node-click="nodeClick" children-loader="childrenLoader"
|
|
||||||
add-item="addItem" remove-item="removeItem" edit-item="editItem">
|
|
||||||
</tree-node>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<div ng-class="tree_class()">
|
|
||||||
<tree-node item="root" adapter="itemAdapter" icon="icon"
|
|
||||||
folder-open="folderOpen" folder-close="folderClose"
|
|
||||||
node-click="nodeClick" children-loader="childrenLoader"
|
|
||||||
add-item="addItem" remove-item="removeItem" edit-item="editItem">
|
|
||||||
</tree-node>
|
|
||||||
</div>
|
|
|
@ -1,33 +0,0 @@
|
||||||
.tree {
|
|
||||||
@node-height: 16px;
|
|
||||||
overflow: auto;
|
|
||||||
.node {
|
|
||||||
width: 100%;
|
|
||||||
.directory-level {
|
|
||||||
position: relative;
|
|
||||||
padding-right: 4px;
|
|
||||||
white-space: nowrap;
|
|
||||||
font-size: @node-height;
|
|
||||||
line-height: @node-height;
|
|
||||||
>.icon {
|
|
||||||
height: @node-height;
|
|
||||||
}
|
|
||||||
.operation {
|
|
||||||
display: inline;
|
|
||||||
margin-left: 20px;
|
|
||||||
visibility: hidden;
|
|
||||||
img {
|
|
||||||
height: @node-height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
.operation {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.sub-node {
|
|
||||||
padding-left: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"directory": "bower_components"
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"curly": true,
|
|
||||||
"eqeqeq": true,
|
|
||||||
"immed": true,
|
|
||||||
"latedef": true,
|
|
||||||
"newcap": true,
|
|
||||||
"noarg": true,
|
|
||||||
"sub": true,
|
|
||||||
"boss": true,
|
|
||||||
"eqnull": true
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
node_modules
|
|
||||||
bower_components
|
|
||||||
demo/bower_components
|
|
|
@ -1,13 +0,0 @@
|
||||||
language: node_js
|
|
||||||
node_js:
|
|
||||||
- "0.8"
|
|
||||||
- "0.10"
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- export DISPLAY=:99.0
|
|
||||||
- sh -e /etc/init.d/xvfb start
|
|
||||||
- npm install -g karma bower grunt-cli
|
|
||||||
- bower install
|
|
||||||
- npm install
|
|
||||||
|
|
||||||
script: "grunt"
|
|
|
@ -1,8 +0,0 @@
|
||||||
CONTRIBUTING
|
|
||||||
============
|
|
||||||
|
|
||||||
* Open a [Pull Request (PR)](https://github.com/angular-ui/ui-select2/pull/new/master)
|
|
||||||
* Make sure your PR is on a **new branch** you created off of the latest version of master
|
|
||||||
* Do **not** open a PR from your master branch
|
|
||||||
* Open a PR to start a discussion even if the code isn't finished (easier to collect feedback this way)
|
|
||||||
* Make sure all previous tests pass and add new tests for added behaviors
|
|
|
@ -1,59 +0,0 @@
|
||||||
module.exports = function (grunt) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var initConfig;
|
|
||||||
|
|
||||||
// Loading external tasks
|
|
||||||
require('load-grunt-tasks')(grunt);
|
|
||||||
|
|
||||||
// Project configuration.
|
|
||||||
initConfig = {
|
|
||||||
bower: 'bower_components',
|
|
||||||
pkg: grunt.file.readJSON('package.json'),
|
|
||||||
watch: {
|
|
||||||
test: {
|
|
||||||
// Lint & run unit tests in Karma
|
|
||||||
// Just running `$ grunt watch` will only lint your code; to run tests
|
|
||||||
// on watch, use `$ grunt watch:karma` to start a Karma server first
|
|
||||||
files: ['src/select2.js', 'test/select2Spec.js'],
|
|
||||||
tasks: ['jshint', 'karma:unit:run']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
karma: {
|
|
||||||
options: {
|
|
||||||
configFile: 'test/karma.conf.js',
|
|
||||||
browsers: ['Firefox', 'PhantomJS']
|
|
||||||
},
|
|
||||||
unit: {
|
|
||||||
singleRun: true
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
autoWatch: true
|
|
||||||
},
|
|
||||||
server: {
|
|
||||||
background: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
jshint: {
|
|
||||||
all:[
|
|
||||||
'gruntFile.js',
|
|
||||||
'src/**/*.js',
|
|
||||||
'test/**/*Spec.js'
|
|
||||||
],
|
|
||||||
options: {
|
|
||||||
jshintrc: '.jshintrc'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
changelog: {
|
|
||||||
options: {
|
|
||||||
dest: 'CHANGELOG.md'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Register tasks
|
|
||||||
grunt.registerTask('default', ['jshint', 'karma:unit']);
|
|
||||||
grunt.registerTask('watch', ['jshint', 'karma:watch']);
|
|
||||||
|
|
||||||
grunt.initConfig(initConfig);
|
|
||||||
};
|
|
|
@ -1,21 +0,0 @@
|
||||||
The MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2012 the AngularUI Team, http://angular-ui.github.com
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
|
@ -1,173 +0,0 @@
|
||||||
ui-select2 [![Build Status](https://travis-ci.org/angular-ui/ui-select2.png)](https://travis-ci.org/angular-ui/ui-select2)
|
|
||||||
==========
|
|
||||||
This directive allows you to enhance your select elements with behaviour from the [select2](http://ivaynberg.github.io/select2/) library.
|
|
||||||
|
|
||||||
# Requirements
|
|
||||||
|
|
||||||
- [AngularJS](http://angularjs.org/)
|
|
||||||
- [JQuery](http://jquery.com/)
|
|
||||||
- [Select2](http://ivaynberg.github.io/select2/)
|
|
||||||
|
|
||||||
## Setup
|
|
||||||
|
|
||||||
1. Install **Karma**, **Grunt** and **Bower**
|
|
||||||
`$ npm install -g karma grunt-cli bower`
|
|
||||||
2. Install development dependencies
|
|
||||||
`$ npm install`
|
|
||||||
3. Install components
|
|
||||||
`$ bower install`
|
|
||||||
4. ???
|
|
||||||
5. Profit!
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
We use [Grunt](http://gruntjs.com/) to check for JavaScript syntax errors and execute all unit tests. To run Grunt, simply execute:
|
|
||||||
|
|
||||||
`$ grunt`
|
|
||||||
|
|
||||||
This will lint and test the code, then exit. To have Grunt stay open and automatically lint and test your files whenever you make a code change, use:
|
|
||||||
|
|
||||||
`$ grunt karma:server watch`
|
|
||||||
|
|
||||||
This will start a Karma server in the background and run unit tests in Firefox and PhantomJS whenever the source code or spec file is saved.
|
|
||||||
|
|
||||||
# Usage
|
|
||||||
|
|
||||||
We use [bower](https://github.com/bower/bower) for dependency management. Install AngularUI Select2 into your project by running the command
|
|
||||||
|
|
||||||
`$ bower install angular-ui-select2`
|
|
||||||
|
|
||||||
If you use a `bower.json` file in your project, you can have Bower save ui-select2 as a dependency by passing the `--save` or `--save-dev` flag with the above command.
|
|
||||||
|
|
||||||
This will copy the ui-select2 files into your `bower_components` folder, along with its dependencies. Load the script files in your application:
|
|
||||||
```html
|
|
||||||
<link rel="stylesheet" href="bower_components/select2/select2.css">
|
|
||||||
<script type="text/javascript" src="bower_components/jquery/jquery.js"></script>
|
|
||||||
<script type="text/javascript" src="bower_components/select2/select2.js"></script>
|
|
||||||
<script type="text/javascript" src="bower_components/angular/angular.js"></script>
|
|
||||||
<script type="text/javascript" src="bower_components/angular-ui-select2/src/select2.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
(Note that `jquery` must be loaded before `angular` so that it doesn't use `jqLite` internally)
|
|
||||||
|
|
||||||
|
|
||||||
Add the select2 module as a dependency to your application module:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var myAppModule = angular.module('MyApp', ['ui.select2']);
|
|
||||||
```
|
|
||||||
|
|
||||||
Apply the directive to your form elements:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<select ui-select2 ng-model="select2" data-placeholder="Pick a number">
|
|
||||||
<option value=""></option>
|
|
||||||
<option value="one">First</option>
|
|
||||||
<option value="two">Second</option>
|
|
||||||
<option value="three">Third</option>
|
|
||||||
</select>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Options
|
|
||||||
|
|
||||||
All the select2 options can be passed through the directive. You can read more about the supported list of options and what they do on the [Select2 Documentation Page](http://ivaynberg.github.com/select2/)
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
myAppModule.controller('MyController', function($scope) {
|
|
||||||
$scope.select2Options = {
|
|
||||||
allowClear:true
|
|
||||||
};
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
```html
|
|
||||||
<select ui-select2="select2Options" ng-model="select2">
|
|
||||||
<option value="one">First</option>
|
|
||||||
<option value="two">Second</option>
|
|
||||||
<option value="three">Third</option>
|
|
||||||
</select>
|
|
||||||
```
|
|
||||||
|
|
||||||
Some times it may make sense to specify the options in the template file.
|
|
||||||
|
|
||||||
```html
|
|
||||||
<select ui-select2="{ allowClear: true}" ng-model="select2">
|
|
||||||
<option value="one">First</option>
|
|
||||||
<option value="two">Second</option>
|
|
||||||
<option value="three">Third</option>
|
|
||||||
</select>
|
|
||||||
```
|
|
||||||
|
|
||||||
To define global defaults, you can configure the `uiSelect2Config` injectable:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
myAppModule.run(['uiSelect2Config', function(uiSelect2Config) {
|
|
||||||
uiSelect2Config.placeholder = "Placeholder text";
|
|
||||||
}]);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Working with ng-model
|
|
||||||
|
|
||||||
The ui-select2 directive plays nicely with ng-model and validation directives such as ng-required.
|
|
||||||
|
|
||||||
If you add the ng-model directive to same the element as ui-select2 then the picked option is automatically synchronized with the model value.
|
|
||||||
|
|
||||||
## Working with dynamic options
|
|
||||||
`ui-select2` is incompatible with `<select ng-options>`. For the best results use `<option ng-repeat>` instead.
|
|
||||||
```html
|
|
||||||
<select ui-select2 ng-model="select2" data-placeholder="Pick a number">
|
|
||||||
<option value=""></option>
|
|
||||||
<option ng-repeat="number in range" value="{{number.value}}">{{number.text}}</option>
|
|
||||||
</select>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Working with placeholder text
|
|
||||||
In order to properly support the Select2 placeholder, create an empty `<option>` tag at the top of the `<select>` and either set a `data-placeholder` on the select element or pass a `placeholder` option to Select2.
|
|
||||||
```html
|
|
||||||
<select ui-select2 ng-model="number" data-placeholder="Pick a number">
|
|
||||||
<option value=""></option>
|
|
||||||
<option value="one">First</option>
|
|
||||||
<option value="two">Second</option>
|
|
||||||
<option value="three">Third</option>
|
|
||||||
</select>
|
|
||||||
```
|
|
||||||
|
|
||||||
## ng-required directive
|
|
||||||
|
|
||||||
If you apply the required directive to element then the form element is invalid until an option is selected.
|
|
||||||
|
|
||||||
Note: Remember that the ng-required directive must be explicitly set, i.e. to "true". This is especially true on divs:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<select ui-select2 ng-model="number" data-placeholder="Pick a number" ng-required="true">
|
|
||||||
<option value=""></option>
|
|
||||||
<option value="one">First</option>
|
|
||||||
<option value="two">Second</option>
|
|
||||||
<option value="three">Third</option>
|
|
||||||
</select>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Using simple tagging mode
|
|
||||||
|
|
||||||
When AngularJS View-Model tags are stored as a list of strings, setting
|
|
||||||
the ui-select2 specific option `simple_tags` will allow to keep the model
|
|
||||||
as a list of strings, and not convert it into a list of Select2 tag objects.
|
|
||||||
|
|
||||||
```html
|
|
||||||
<input
|
|
||||||
type="hidden"
|
|
||||||
ui-select2="select2Options"
|
|
||||||
ng-model="list_of_string"
|
|
||||||
>
|
|
||||||
```
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
myAppModule.controller('MyController', function($scope) {
|
|
||||||
$scope.list_of_string = ['tag1', 'tag2']
|
|
||||||
$scope.select2Options = {
|
|
||||||
'multiple': true,
|
|
||||||
'simple_tags': true,
|
|
||||||
'tags': ['tag1', 'tag2', 'tag3', 'tag4'] // Can be empty list.
|
|
||||||
};
|
|
||||||
});
|
|
||||||
```
|
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"author": "AngularUI",
|
|
||||||
"name": "angular-ui-select2",
|
|
||||||
"version": "0.0.5",
|
|
||||||
"homepage": "http://angular-ui.github.com",
|
|
||||||
"keywords": [
|
|
||||||
"angular",
|
|
||||||
"angularui",
|
|
||||||
"select2"
|
|
||||||
],
|
|
||||||
"main": "./src/select2.js",
|
|
||||||
"dependencies": {
|
|
||||||
"angular": ">=1.2.0",
|
|
||||||
"select2": "~3.4",
|
|
||||||
"jquery": ">=1.6.4"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"angular-mocks": ">=1.0.2"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,114 +0,0 @@
|
||||||
|
|
||||||
var app = angular.module('angular-ui-select2-demo', ['ui.select2']);
|
|
||||||
|
|
||||||
app.controller('MainCtrl', function ($scope, $element) {
|
|
||||||
|
|
||||||
var states = [
|
|
||||||
{ text: 'Alaskan/Hawaiian Time Zone', children: [
|
|
||||||
{ id: 'AK', text: 'Alaska' },
|
|
||||||
{ id: 'HI', text: 'Hawaii' }
|
|
||||||
]},
|
|
||||||
{ text: 'Pacific Time Zone', children: [
|
|
||||||
{ id: 'CA', text: 'California' },
|
|
||||||
{ id: 'NV', text: 'Nevada' },
|
|
||||||
{ id: 'OR', text: 'Oregon' },
|
|
||||||
{ id: 'WA', text: 'Washington' }
|
|
||||||
]},
|
|
||||||
{ text: 'Mountain Time Zone', children: [
|
|
||||||
{ id: 'AZ', text: 'Arizona' },
|
|
||||||
{ id: 'CO', text: 'Colorado' },
|
|
||||||
{ id: 'ID', text: 'Idaho' },
|
|
||||||
{ id: 'MT', text: 'Montana' },
|
|
||||||
{ id: 'NE', text: 'Nebraska' },
|
|
||||||
{ id: 'NM', text: 'New Mexico' },
|
|
||||||
{ id: 'ND', text: 'North Dakota' },
|
|
||||||
{ id: 'UT', text: 'Utah' },
|
|
||||||
{ id: 'WY', text: 'Wyoming' }
|
|
||||||
]},
|
|
||||||
{ text: 'Central Time Zone', children: [
|
|
||||||
{ id: 'AL', text: 'Alabama' },
|
|
||||||
{ id: 'AR', text: 'Arkansas' },
|
|
||||||
{ id: 'IL', text: 'Illinois' },
|
|
||||||
{ id: 'IA', text: 'Iowa' },
|
|
||||||
{ id: 'KS', text: 'Kansas' },
|
|
||||||
{ id: 'KY', text: 'Kentucky' },
|
|
||||||
{ id: 'LA', text: 'Louisiana' },
|
|
||||||
{ id: 'MN', text: 'Minnesota' },
|
|
||||||
{ id: 'MS', text: 'Mississippi' },
|
|
||||||
{ id: 'MO', text: 'Missouri' },
|
|
||||||
{ id: 'OK', text: 'Oklahoma' },
|
|
||||||
{ id: 'SD', text: 'South Dakota' },
|
|
||||||
{ id: 'TX', text: 'Texas' },
|
|
||||||
{ id: 'TN', text: 'Tennessee' },
|
|
||||||
{ id: 'WI', text: 'Wisconsin' }
|
|
||||||
]},
|
|
||||||
{ text: 'Eastern Time Zone', children: [
|
|
||||||
{ id: 'CT', text: 'Connecticut' },
|
|
||||||
{ id: 'DE', text: 'Delaware' },
|
|
||||||
{ id: 'FL', text: 'Florida' },
|
|
||||||
{ id: 'GA', text: 'Georgia' },
|
|
||||||
{ id: 'IN', text: 'Indiana' },
|
|
||||||
{ id: 'ME', text: 'Maine' },
|
|
||||||
{ id: 'MD', text: 'Maryland' },
|
|
||||||
{ id: 'MA', text: 'Massachusetts' },
|
|
||||||
{ id: 'MI', text: 'Michigan' },
|
|
||||||
{ id: 'NH', text: 'New Hampshire' },
|
|
||||||
{ id: 'NJ', text: 'New Jersey' },
|
|
||||||
{ id: 'NY', text: 'New York' },
|
|
||||||
{ id: 'NC', text: 'North Carolina' },
|
|
||||||
{ id: 'OH', text: 'Ohio' },
|
|
||||||
{ id: 'PA', text: 'Pennsylvania' },
|
|
||||||
{ id: 'RI', text: 'Rhode Island' },
|
|
||||||
{ id: 'SC', text: 'South Carolina' },
|
|
||||||
{ id: 'VT', text: 'Vermont' },
|
|
||||||
{ id: 'VA', text: 'Virginia' },
|
|
||||||
{ id: 'WV', text: 'West Virginia' }
|
|
||||||
]}
|
|
||||||
];
|
|
||||||
|
|
||||||
function findState(id) {
|
|
||||||
for (var i=0; i<states.length; i++) {
|
|
||||||
for (var j=0; j<states[i].children.length; j++) {
|
|
||||||
if (states[i].children[j].id == id) {
|
|
||||||
return states[i].children[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.multi2Value = ['CO', 'WA'];
|
|
||||||
|
|
||||||
$scope.multi = {
|
|
||||||
multiple: true,
|
|
||||||
query: function (query) {
|
|
||||||
query.callback({ results: states });
|
|
||||||
},
|
|
||||||
initSelection: function(element, callback) {
|
|
||||||
var val = $(element).select2('val'),
|
|
||||||
results = [];
|
|
||||||
for (var i=0; i<val.length; i++) {
|
|
||||||
results.push(findState(val[i]));
|
|
||||||
}
|
|
||||||
callback(results);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.placeholders = {
|
|
||||||
placeholder: "Select a State"
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.array = {
|
|
||||||
data: [{id:0,text:'enhancement'},{id:1,text:'bug'},{id:2,text:'duplicate'},{id:3,text:'invalid'},{id:4,text:'wontfix'}]
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.arrayAsync = {
|
|
||||||
query: function (query) {
|
|
||||||
query.callback({ results: states });
|
|
||||||
},
|
|
||||||
initSelection: function(element, callback) {
|
|
||||||
var val = $(element).select2('val');
|
|
||||||
return callback(findState(val));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"name": "angular-ui-select2-demo",
|
|
||||||
"main": "./index.html",
|
|
||||||
"dependencies": {
|
|
||||||
"angular": ">=1.2.0",
|
|
||||||
"select2": "~3.4",
|
|
||||||
"jquery": ">=1.6.4",
|
|
||||||
"bootstrap": "~3.0.3",
|
|
||||||
"angular-ui-select2": "~0.0.5"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,225 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html ng-app="angular-ui-select2-demo">
|
|
||||||
<head>
|
|
||||||
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
|
|
||||||
<link rel="stylesheet" href="bower_components/select2/select2.css">
|
|
||||||
<style>
|
|
||||||
.container {
|
|
||||||
padding-bottom: 4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
border-bottom: 1px solid #ddd;
|
|
||||||
margin-top: 2em;
|
|
||||||
}
|
|
||||||
h3 {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: normal;
|
|
||||||
margin-top: 0.2em;
|
|
||||||
}
|
|
||||||
.select2-container {
|
|
||||||
}
|
|
||||||
label {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: normal;
|
|
||||||
display: block;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
.example.row {
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script src="bower_components/jquery/dist/jquery.js"></script>
|
|
||||||
<script src="bower_components/select2/select2.js"></script>
|
|
||||||
<script src="bower_components/angular/angular.js"></script>
|
|
||||||
<script src="bower_components/angular-ui-select2/src/select2.js"></script>
|
|
||||||
<script src="app.js"></script>
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
var opts=$('#source').html(), opts2='<option></option>'+opts;
|
|
||||||
$('select.populate').each(function() { var e=$(this); e.html(e.hasClass('placeholder')?opts2:opts); });
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container" ng-controller="MainCtrl">
|
|
||||||
|
|
||||||
<article class="row" id="basics">
|
|
||||||
<h2>The Basics</h2>
|
|
||||||
<div class="example row">
|
|
||||||
<div class="col-md-4 left">
|
|
||||||
<label><select></label>
|
|
||||||
<select style="width:300px" ui-select2 ng-model="basicsValue" id="source">
|
|
||||||
<optgroup label="Alaskan/Hawaiian Time Zone">
|
|
||||||
<option value="AK">Alaska</option>
|
|
||||||
<option value="HI">Hawaii</option>
|
|
||||||
</optgroup>
|
|
||||||
<optgroup label="Pacific Time Zone">
|
|
||||||
<option value="CA">California</option>
|
|
||||||
<option value="NV">Nevada</option>
|
|
||||||
<option value="OR">Oregon</option>
|
|
||||||
<option value="WA">Washington</option>
|
|
||||||
</optgroup>
|
|
||||||
<optgroup label="Mountain Time Zone">
|
|
||||||
<option value="AZ">Arizona</option>
|
|
||||||
<option value="CO">Colorado</option>
|
|
||||||
<option value="ID">Idaho</option>
|
|
||||||
<option value="MT">Montana</option>
|
|
||||||
<option value="NE">Nebraska</option>
|
|
||||||
<option value="NM">New Mexico</option>
|
|
||||||
<option value="ND">North Dakota</option>
|
|
||||||
<option value="UT">Utah</option>
|
|
||||||
<option value="WY">Wyoming</option>
|
|
||||||
</optgroup>
|
|
||||||
<optgroup label="Central Time Zone">
|
|
||||||
<option value="AL">Alabama</option>
|
|
||||||
<option value="AR">Arkansas</option>
|
|
||||||
<option value="IL">Illinois</option>
|
|
||||||
<option value="IA">Iowa</option>
|
|
||||||
<option value="KS">Kansas</option>
|
|
||||||
<option value="KY">Kentucky</option>
|
|
||||||
<option value="LA">Louisiana</option>
|
|
||||||
<option value="MN">Minnesota</option>
|
|
||||||
<option value="MS">Mississippi</option>
|
|
||||||
<option value="MO">Missouri</option>
|
|
||||||
<option value="OK">Oklahoma</option>
|
|
||||||
<option value="SD">South Dakota</option>
|
|
||||||
<option value="TX">Texas</option>
|
|
||||||
<option value="TN">Tennessee</option>
|
|
||||||
<option value="WI">Wisconsin</option>
|
|
||||||
</optgroup>
|
|
||||||
<optgroup label="Eastern Time Zone">
|
|
||||||
<option value="CT">Connecticut</option>
|
|
||||||
<option value="DE">Delaware</option>
|
|
||||||
<option value="FL">Florida</option>
|
|
||||||
<option value="GA">Georgia</option>
|
|
||||||
<option value="IN">Indiana</option>
|
|
||||||
<option value="ME">Maine</option>
|
|
||||||
<option value="MD">Maryland</option>
|
|
||||||
<option value="MA">Massachusetts</option>
|
|
||||||
<option value="MI">Michigan</option>
|
|
||||||
<option value="NH">New Hampshire</option>
|
|
||||||
<option value="NJ">New Jersey</option>
|
|
||||||
<option value="NY">New York</option>
|
|
||||||
<option value="NC">North Carolina</option>
|
|
||||||
<option value="OH">Ohio</option>
|
|
||||||
<option value="PA">Pennsylvania</option>
|
|
||||||
<option value="RI">Rhode Island</option>
|
|
||||||
<option value="SC">South Carolina</option>
|
|
||||||
<option value="VT">Vermont</option>
|
|
||||||
<option value="VA">Virginia</option>
|
|
||||||
<option value="WV">West Virginia</option>
|
|
||||||
</optgroup>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8 right">
|
|
||||||
<h3>Value</h3>
|
|
||||||
<pre>{{ basicsValue }}</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<article class="row" id="multi">
|
|
||||||
<h2>Multi-Value</h2>
|
|
||||||
<div class="example row">
|
|
||||||
<div class="col-md-4 left">
|
|
||||||
<label><select multiple></label>
|
|
||||||
<select style="width:300px" ui-select2 multiple ng-model="multiValue" class="populate"></select>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8 right">
|
|
||||||
<h3>Value</h3>
|
|
||||||
<pre>{{ multiValue }}</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="example row">
|
|
||||||
<div class="col-md-4 left">
|
|
||||||
<label>Pre-defined value</label>
|
|
||||||
<input type="hidden" style="width:300px" ui-select2="multi" ng-model="multi2Value"/>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8 right">
|
|
||||||
<h3>Config</h3>
|
|
||||||
<pre><code>{
|
|
||||||
multiple: true,
|
|
||||||
query: function (query) {
|
|
||||||
query.callback({ results: states });
|
|
||||||
},
|
|
||||||
initSelection: function(element, callback) {
|
|
||||||
var val = $(element).select2('val'),
|
|
||||||
results = [];
|
|
||||||
for (var i=0; i<val.length; i++) {
|
|
||||||
results.push(findState(val[i]));
|
|
||||||
}
|
|
||||||
callback(results);
|
|
||||||
}
|
|
||||||
}</code></pre>
|
|
||||||
<h3>Value</h3>
|
|
||||||
<pre>{{ multi2Value }}</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<article class="row" id="placeholders">
|
|
||||||
<h2>Placeholders</h2>
|
|
||||||
<div class="example row">
|
|
||||||
<div class="col-md-4 left">
|
|
||||||
<label>Using data-attribute</label>
|
|
||||||
<select style="width:300px" ui-select2 ng-model="placeholdersValue" class="populate placeholder" data-placeholder="Select a State"></select>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8 right">
|
|
||||||
<h3>Value</h3>
|
|
||||||
<pre>{{ placeholdersValue }}</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="example row">
|
|
||||||
<div class="col-md-4 left">
|
|
||||||
<label>Multiple, using config</label>
|
|
||||||
<select style="width:300px" ui-select2="placeholders" multiple ng-model="placeholdersMultiValue" class="populate"></select>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8 right">
|
|
||||||
<h3>Config</h3>
|
|
||||||
<pre><code>{{ placeholders }}</code></pre>
|
|
||||||
<h3>Value</h3>
|
|
||||||
<pre>{{ placeholdersMultiValue }}</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<article class="row" id="array">
|
|
||||||
<h2>Array Data</h2>
|
|
||||||
<div class="example row">
|
|
||||||
<div class="col-md-4 left">
|
|
||||||
<label>Simple</label>
|
|
||||||
<input type="hidden" style="width:300px" ui-select2="array" ng-model="arrayValue"/>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8 right">
|
|
||||||
<h3>Config</h3>
|
|
||||||
<pre><code>{{ array }}</code></pre>
|
|
||||||
<h3>Value</h3>
|
|
||||||
<pre>{{ arrayValue }}</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="example row">
|
|
||||||
<div class="col-md-4 left">
|
|
||||||
<label>Asynchronous</label>
|
|
||||||
<input type="hidden" style="width:300px" ui-select2="arrayAsync" ng-model="arrayAsyncValue"/>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8 right">
|
|
||||||
<h3>Config</h3>
|
|
||||||
<pre><code>{
|
|
||||||
query: function (query) {
|
|
||||||
query.callback({ results: states });
|
|
||||||
},
|
|
||||||
initSelection: function(element, callback) {
|
|
||||||
var val = $(element).select2('val');
|
|
||||||
return callback(findState(val));
|
|
||||||
}
|
|
||||||
}</code></pre>
|
|
||||||
<h3>Value</h3>
|
|
||||||
<pre>{{ arrayAsyncValue }}</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,47 +0,0 @@
|
||||||
<section id="directives-select2">
|
|
||||||
<div class="page-header">
|
|
||||||
<h1>Select2</h1>
|
|
||||||
<small><a href="http://ivaynberg.github.com/select2/">Select2</a> is inspired by <a href="http://harvesthq.github.com/chosen">Chosen</a></small>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="span6">
|
|
||||||
<h3>Demo</h3>
|
|
||||||
<div class="well">
|
|
||||||
<p>Value is: {{select2}} <a ng-click="select2='two'">(choose second)</a></p>
|
|
||||||
<select ui-select2 ng-model="select2" data-placeholder="Pick a number">
|
|
||||||
<option value=""></option>
|
|
||||||
<option value="one">First</option>
|
|
||||||
<option value="two">Second</option>
|
|
||||||
<option value="three">Third</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="well">
|
|
||||||
<p>Value is: {{select2multiple}} <a ng-click="select2multiple=['two']">(choose second)</a></p>
|
|
||||||
<select ui-select2 ng-model="select2multiple" data-placeholder="Pick a number" multiple>
|
|
||||||
<option value="one">First</option>
|
|
||||||
<option value="two">Second</option>
|
|
||||||
<option value="three">Third</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="span6">
|
|
||||||
<h3>Options</h3>
|
|
||||||
<p>You can pass an object to Select2 as the expression: <code>ui-select2="{allowClear:true}"</code> that will be passed directly to <code>$.fn.select2()</code>. You can read more about the supported list of options and what they do on the <a href="http://ivaynberg.github.com/select2/">Select2 Documentation Page</a>. AngularUI will leverage properties passed to Select2 for any complex behavior, there are no parameters necessary for that are specific to AngularUI.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="alert alert-info"><i class="icon-info-sign"></i> <code>ui-select2</code> is incompatible with <code><select ng-options></code>. For the best results use <code><option ng-repeat></code> instead</p>
|
|
||||||
<p class="alert alert-info"><i class="icon-info-sign"></i> In order to properly support the Select2 placeholder, create an empty <code><option></code> tag at the top of the <code><select></code> and either set a <code>data-placeholder</code> on the select element or pass a <code>placeholder</code> option to Select2.</p>
|
|
||||||
|
|
||||||
<h3>How?</h3>
|
|
||||||
<pre class="prettyprint linenums" ng-non-bindable>
|
|
||||||
<p>Value is: {{select2}} <a ng-click="select2='two'">(choose second)</a></p>
|
|
||||||
<select ui-select2 ng-model="select2">
|
|
||||||
<option value="">Pick a number</option>
|
|
||||||
<option value="one">First</option>
|
|
||||||
<option value="two">Second</option>
|
|
||||||
<option value="three">Third</option>
|
|
||||||
</select>
|
|
||||||
</pre>
|
|
||||||
<p>Or try playing around with this <a href="http://plnkr.co/edit/gist:4279651?p=preview">sandbox demo</a> to see how AJAX works</p>
|
|
||||||
</section>
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue