diff --git a/gulpfile.js b/gulpfile.js
index 02446315..922ac858 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -17,9 +17,14 @@
*/
var gulp = require("gulp"),
+ gutil = require("gulp-util"),
plug = require("gulp-load-plugins")(),
argv = require("yargs").argv,
- header = require("gulp-header");
+ header = require("gulp-header"),
+ webpack = require("webpack"),
+ WebpackDevServer = require("webpack-dev-server"),
+ webpackConfig = require("./webpack.config.js"),
+ webpackStream = require('webpack-stream');
var plumberOptions = {
errorHandler: plug.notify.onError("Error: <%= error.message %>")
@@ -47,6 +52,38 @@ var licenseHeader = [
""
].join('\n');
+
+
+//gulp.task('webpack', [], function () {
+// return gulp.src(path.ALL) // gulp looks for all source files under specified path
+// .pipe(sourcemaps.init()) // creates a source map which would be very helpful for debugging by maintaining the actual source code structure
+// .pipe(webpackStream(webpackConfig)) // blend in the webpack config into the source files
+// .pipe(uglify())// minifies the code for better compression
+// .pipe(sourcemaps.write())
+// .pipe(gulp.dest(path.DEST_BUILD));
+//});
+
+
+gulp.task("webpack-dev-server", function (callback) {
+ // Start a webpack-dev-server
+ //webpackConfig.entry.app.unshift("webpack-dev-server/client?http://localhost:8080");
+ var compiler = webpack(webpackConfig);
+
+ new WebpackDevServer(compiler, {
+ // server and middleware options
+ }).listen(8080, "localhost", function (err) {
+ if (err) throw new gutil.PluginError("webpack-dev-server", err);
+ // Server listening
+ gutil.log("[webpack-dev-server]", "http://localhost:8080/webpack-dev-server/index.html");
+
+ // keep the server alive or continue?
+ // callback();
+ });
+});
+
+
+// ============================
+
gulp.task("scripts-app", function () {
var paths = [
"resources/assets/scripts/app/**/*.{coffee,js}",
@@ -220,6 +257,13 @@ gulp.task("watch", ["build"], function () {
gulp.watch("resources/assets/styles/**/*.{css,less}", ["styles-app"]);
});
+
+gulp.task('watch-webpack', function () {
+ gulp.watch(path.ALL, ['webpack']);
+ gulp.run('webpack-dev-server');
+});
+
+
function endsWith(str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
diff --git a/package.json b/package.json
index 461cc7c8..ea9e79da 100644
--- a/package.json
+++ b/package.json
@@ -1,22 +1,23 @@
{
"name": "pony.fm",
"version": "1.0.0",
- "license": "AGPL",
+ "license": "AGPL-3.0",
"repository": {
"type": "git",
"url": "ssh://git@phabricator.poniverse.net/diffusion/PF/pony-fm.git"
},
"packages": {},
- "dependencies": {
- "gulp-header": "^1.7.1"
- },
+ "dependencies": {},
"devDependencies": {
+ "angular": "^1.5.0",
+ "coffee-loader": "^0.7.2",
"gulp": "^3.9.0",
"gulp-angular-templatecache": "^1.6.0",
"gulp-autoprefixer": "^2.2.0",
"gulp-cached": "^1.0.4",
"gulp-coffee": "^2.3.1",
"gulp-concat": "^2.5.2",
+ "gulp-header": "^1.7.1",
"gulp-if": "^1.2.5",
"gulp-less": "^3.0.3",
"gulp-livereload": "^3.8.0",
@@ -27,7 +28,14 @@
"gulp-plumber": "^1.0.0",
"gulp-sourcemaps": "^1.5.1",
"gulp-uglify": "^1.2.0",
- "gulp-util": "^3.0.4",
+ "gulp-util": "^3.0.7",
+ "gulp-webpack": "^1.5.0",
+ "jquery": "^2.2.0",
+ "jquery-ui": "^1.10.5",
+ "script-loader": "^0.6.1",
+ "webpack": "^1.12.13",
+ "webpack-dev-server": "^1.14.1",
+ "webpack-stream": "^3.1.0",
"yargs": "^3.7.2"
}
}
diff --git a/resources/assets/scripts/app/app.coffee b/resources/assets/scripts/app/app.coffee
index d896d146..7974c029 100644
--- a/resources/assets/scripts/app/app.coffee
+++ b/resources/assets/scripts/app/app.coffee
@@ -14,25 +14,105 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+
+require 'script!../base/jquery-2.0.2'
+require 'script!../base/jquery-ui'
+angular = require 'angular'
+
+require 'script!../base/angular-ui-date'
+require '../base/angular-ui-router'
+require '../base/angular-ui-sortable'
+require '../base/angularytics'
+require '../base/jquery.colorbox'
+require '../base/jquery.cookie'
+require '../base/jquery.timeago'
+require '../base/jquery.viewport'
+require 'script!../base/marked'
+require 'script!../base/moment'
+require '../base/soundmanager2-nodebug'
+require 'script!../base/tumblr'
+require '../base/ui-bootstrap-tpls-0.4.0'
+require 'script!../base/underscore'
+
+require '../shared/init.coffee'
+require '../shared/jquery-extensions'
+require '../shared/layout.coffee'
+require '../shared/pfm-angular-marked'
+require '../shared/pfm-angular-sanitize'
+require 'script!../shared/underscore-extensions'
+
+
+ponyfm = angular.module 'ponyfm', ['ui.bootstrap', 'ui.state', 'ui.date', 'ui.sortable', 'angularytics', 'ngSanitize', 'hc.marked']
window.pfm.preloaders = {}
-module = angular.module 'ponyfm', ['ui.bootstrap', 'ui.state', 'ui.date', 'ui.sortable', 'angularytics', 'ngSanitize', 'hc.marked']
+##require './controllers/'+name+'.coffee'
+#require "./controllers/account-albums-edit"
+#require "./controllers/account-albums"
+#require "./controllers/account-image-select"
+#require "./controllers/account-playlists"
+#require "./controllers/account-settings"
+#require "./controllers/account-track"
+#require "./controllers/account-tracks"
+#require "./controllers/admin-genres"
+#require "./controllers/album"
+#require "./controllers/albums-list"
+#require "./controllers/albums"
+#require "./controllers/application"
+#require "./controllers/artist-content"
+#require "./controllers/artist-favourites"
+#require "./controllers/artist-profile"
+#require "./controllers/artist"
+#require "./controllers/artists-list"
+#require "./controllers/artists"
+#require "./controllers/credits"
+#require "./controllers/dashboard"
+#require "./controllers/favourites-albums"
+#require "./controllers/favourites-playlists"
+#require "./controllers/favourites-tracks"
+#require "./controllers/home"
+#require "./controllers/login"
+#require "./controllers/playlist-form"
+#require "./controllers/playlist"
+#require "./controllers/playlists-list"
+#require "./controllers/playlists"
+#require "./controllers/sidebar"
+#require "./controllers/track-edit"
+#require "./controllers/track-show"
+#require "./controllers/track"
+#require "./controllers/tracks-list"
+#require "./controllers/tracks"
+#require "./controllers/uploader"
+
+
+requireAll = (r) ->
+ r.keys().forEach(r)
+
+requireAll(require.context('./controllers/', false, /\.coffee$/));
+requireAll(require.context('./directives/', false, /\.coffee$/));
+requireAll(require.context('./filters/', false, /\.coffee$/));
+requireAll(require.context('./services/', false, /\.coffee$/));
+
+#require './directives/'+name
+#require './filters/'+name
+#require './services/'+name
+
+
if window.pfm.environment == 'production'
- module.run [
+ ponyfm.run [
'Angularytics',
(analytics) ->
analytics.init()
]
-module.run [
+ponyfm.run [
'$rootScope',
($rootScope) ->
$rootScope.$on '$stateChangeStart', (event, toState, toParams, fromState, fromParams) ->
$rootScope.description = ''
]
-module.config [
+ponyfm.config [
'$locationProvider', '$stateProvider', '$dialogProvider', 'AngularyticsProvider', '$httpProvider', '$sceDelegateProvider', 'markedProvider'
(location, state, $dialogProvider, analytics, $httpProvider, $sceDelegateProvider, markedProvider) ->
@@ -330,3 +410,5 @@ module.config [
backdropClick: false
]
+
+module.exports = ponyfm
diff --git a/resources/assets/scripts/app/controllers/account-albums-edit.coffee b/resources/assets/scripts/app/controllers/account-albums-edit.coffee
index 364b3e53..2cc5bf1d 100644
--- a/resources/assets/scripts/app/controllers/account-albums-edit.coffee
+++ b/resources/assets/scripts/app/controllers/account-albums-edit.coffee
@@ -24,7 +24,7 @@ window.pfm.preloaders['account-albums-edit'] = [
$.when.all defs
]
-angular.module('ponyfm').controller "account-albums-edit", [
+module.exports = angular.module('ponyfm').controller "account-albums-edit", [
'$scope', '$state', '$dialog', 'account-albums'
($scope, $state, $dialog, albums) ->
$scope.isNew = $state.params.album_id == undefined
diff --git a/resources/assets/scripts/app/controllers/account-albums.coffee b/resources/assets/scripts/app/controllers/account-albums.coffee
index 8c56c067..877f14b1 100644
--- a/resources/assets/scripts/app/controllers/account-albums.coffee
+++ b/resources/assets/scripts/app/controllers/account-albums.coffee
@@ -20,7 +20,7 @@ window.pfm.preloaders['account-albums'] = [
$.when.all [tracks.refresh('published=true&in_album=false', true), albums.refresh(true)]
]
-angular.module('ponyfm').controller "account-albums", [
+module.exports = angular.module('ponyfm').controller "account-albums", [
'$scope', '$state', 'account-albums', 'account-tracks'
($scope, $state, albums, tracks) ->
diff --git a/resources/assets/scripts/app/controllers/account-image-select.coffee b/resources/assets/scripts/app/controllers/account-image-select.coffee
index 0678b4a8..a790759e 100644
--- a/resources/assets/scripts/app/controllers/account-image-select.coffee
+++ b/resources/assets/scripts/app/controllers/account-image-select.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').controller "account-image-select", [
+module.exports = angular.module('ponyfm').controller "account-image-select", [
'$scope'
($scope) ->
$scope.images = []
diff --git a/resources/assets/scripts/app/controllers/account-playlists.coffee b/resources/assets/scripts/app/controllers/account-playlists.coffee
index f8538652..9805075f 100644
--- a/resources/assets/scripts/app/controllers/account-playlists.coffee
+++ b/resources/assets/scripts/app/controllers/account-playlists.coffee
@@ -19,7 +19,7 @@ window.pfm.preloaders['account-playlists'] = [
(playlists) -> playlists.refreshOwned true
]
-angular.module('ponyfm').controller "account-playlists", [
+module.exports = angular.module('ponyfm').controller "account-playlists", [
'$scope', 'auth', '$dialog', 'playlists'
($scope, auth, $dialog, playlists) ->
$scope.playlists = []
diff --git a/resources/assets/scripts/app/controllers/account-settings.coffee b/resources/assets/scripts/app/controllers/account-settings.coffee
index 117c71b0..4f7a03d8 100644
--- a/resources/assets/scripts/app/controllers/account-settings.coffee
+++ b/resources/assets/scripts/app/controllers/account-settings.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').controller "account-settings", [
+module.exports = angular.module('ponyfm').controller "account-settings", [
'$scope', 'auth'
($scope, auth) ->
$scope.settings = {}
diff --git a/resources/assets/scripts/app/controllers/account-track.coffee b/resources/assets/scripts/app/controllers/account-track.coffee
index 274a5122..4c6b1782 100644
--- a/resources/assets/scripts/app/controllers/account-track.coffee
+++ b/resources/assets/scripts/app/controllers/account-track.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').controller "account-track", [
+module.exports = angular.module('ponyfm').controller "account-track", [
'$scope', '$state'
($scope, $state) ->
# All the fun stuff happens in the pfmTrackEditor directive.
diff --git a/resources/assets/scripts/app/controllers/account-tracks.coffee b/resources/assets/scripts/app/controllers/account-tracks.coffee
index 5deda9ba..520abd48 100644
--- a/resources/assets/scripts/app/controllers/account-tracks.coffee
+++ b/resources/assets/scripts/app/controllers/account-tracks.coffee
@@ -20,7 +20,7 @@ window.pfm.preloaders['account-tracks'] = [
$.when.all [tracks.refresh(null, true), albums.refresh(true), taxonomies.refresh()]
]
-angular.module('ponyfm').controller "account-tracks", [
+module.exports = angular.module('ponyfm').controller "account-tracks", [
'$scope', '$state', 'taxonomies', '$dialog', 'lightbox', 'account-albums', 'account-tracks'
($scope, $state, taxonomies, $dialog, lightbox, albums, tracks) ->
$scope.data =
diff --git a/resources/assets/scripts/app/controllers/admin-genres.coffee b/resources/assets/scripts/app/controllers/admin-genres.coffee
index 4677ff15..815b3562 100644
--- a/resources/assets/scripts/app/controllers/admin-genres.coffee
+++ b/resources/assets/scripts/app/controllers/admin-genres.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').controller 'admin-genres', [
+module.exports = angular.module('ponyfm').controller 'admin-genres', [
'$scope', '$state', 'admin-genres'
($scope, $state, genres) ->
diff --git a/resources/assets/scripts/app/controllers/album.coffee b/resources/assets/scripts/app/controllers/album.coffee
index 387a2bd9..122ef367 100644
--- a/resources/assets/scripts/app/controllers/album.coffee
+++ b/resources/assets/scripts/app/controllers/album.coffee
@@ -20,7 +20,7 @@ window.pfm.preloaders['album'] = [
$.when.all [albums.fetch $state.params.id, playlists.refreshOwned(true)]
]
-angular.module('ponyfm').controller "album", [
+module.exports = angular.module('ponyfm').controller "album", [
'$scope', '$rootScope', 'albums', '$state', 'playlists', 'auth', '$dialog', 'download-cached', '$window', '$timeout'
($scope, $rootScope, albums, $state, playlists, auth, $dialog, cachedAlbum, $window, $timeout) ->
album = null
diff --git a/resources/assets/scripts/app/controllers/albums-list.coffee b/resources/assets/scripts/app/controllers/albums-list.coffee
index de468572..52973e2e 100644
--- a/resources/assets/scripts/app/controllers/albums-list.coffee
+++ b/resources/assets/scripts/app/controllers/albums-list.coffee
@@ -20,7 +20,7 @@ window.pfm.preloaders['albums-list'] = [
albums.fetchList($state.params.page, true)
]
-angular.module('ponyfm').controller "albums-list", [
+module.exports = angular.module('ponyfm').controller "albums-list", [
'$scope', 'albums', '$state'
($scope, albums, $state) ->
albums.fetchList($state.params.page).done (list) ->
diff --git a/resources/assets/scripts/app/controllers/albums.coffee b/resources/assets/scripts/app/controllers/albums.coffee
index 447f3943..28f44a30 100644
--- a/resources/assets/scripts/app/controllers/albums.coffee
+++ b/resources/assets/scripts/app/controllers/albums.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').controller "albums", [
+module.exports = angular.module('ponyfm').controller "albums", [
'$scope', 'albums', '$state'
($scope, albums, $state) ->
diff --git a/resources/assets/scripts/app/controllers/application.coffee b/resources/assets/scripts/app/controllers/application.coffee
index 15b80d0b..9bcfc1cd 100644
--- a/resources/assets/scripts/app/controllers/application.coffee
+++ b/resources/assets/scripts/app/controllers/application.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').controller "application", [
+module.exports = angular.module('ponyfm').controller "application", [
'$scope', 'auth', '$location', 'upload', '$state', '$stateParams', '$injector', '$rootScope', 'playlists'
($scope, auth, $location, upload, $state, $stateParams, $injector, $rootScope, playlists) ->
$scope.auth = auth.data
diff --git a/resources/assets/scripts/app/controllers/artist-content.coffee b/resources/assets/scripts/app/controllers/artist-content.coffee
index 9fefea2b..aa4a8833 100644
--- a/resources/assets/scripts/app/controllers/artist-content.coffee
+++ b/resources/assets/scripts/app/controllers/artist-content.coffee
@@ -20,7 +20,7 @@ window.pfm.preloaders['artist-content'] = [
$.when.all [artists.fetch($state.params.slug), artists.fetchContent($state.params.slug, true)]
]
-angular.module('ponyfm').controller "artist-content", [
+module.exports = angular.module('ponyfm').controller "artist-content", [
'$scope', 'artists', '$state'
($scope, artists, $state) ->
artists.fetchContent($state.params.slug)
diff --git a/resources/assets/scripts/app/controllers/artist-favourites.coffee b/resources/assets/scripts/app/controllers/artist-favourites.coffee
index ca29dc42..d3a00d00 100644
--- a/resources/assets/scripts/app/controllers/artist-favourites.coffee
+++ b/resources/assets/scripts/app/controllers/artist-favourites.coffee
@@ -20,7 +20,7 @@ window.pfm.preloaders['artist-favourites'] = [
$.when.all [artists.fetch($state.params.slug), artists.fetchFavourites($state.params.slug, true)]
]
-angular.module('ponyfm').controller "artist-favourites", [
+module.exports = angular.module('ponyfm').controller "artist-favourites", [
'$scope', 'artists', '$state'
($scope, artists, $state) ->
artists.fetchFavourites($state.params.slug).done (artistResponse) ->
diff --git a/resources/assets/scripts/app/controllers/artist-profile.coffee b/resources/assets/scripts/app/controllers/artist-profile.coffee
index 368efcef..09587299 100644
--- a/resources/assets/scripts/app/controllers/artist-profile.coffee
+++ b/resources/assets/scripts/app/controllers/artist-profile.coffee
@@ -20,7 +20,7 @@ window.pfm.preloaders['artist-profile'] = [
artists.fetch $state.params.slug, true
]
-angular.module('ponyfm').controller "artist-profile", [
+module.exports = angular.module('ponyfm').controller "artist-profile", [
'$scope', 'artists', '$state'
($scope, artists, $state) ->
]
diff --git a/resources/assets/scripts/app/controllers/artist.coffee b/resources/assets/scripts/app/controllers/artist.coffee
index 295a937b..64a3c600 100644
--- a/resources/assets/scripts/app/controllers/artist.coffee
+++ b/resources/assets/scripts/app/controllers/artist.coffee
@@ -20,7 +20,7 @@ window.pfm.preloaders['artist'] = [
artists.fetch $state.params.slug, true
]
-angular.module('ponyfm').controller "artist", [
+module.exports = angular.module('ponyfm').controller "artist", [
'$scope', 'artists', '$state', 'follow'
($scope, artists, $state, follow) ->
artists.fetch($state.params.slug)
diff --git a/resources/assets/scripts/app/controllers/artists-list.coffee b/resources/assets/scripts/app/controllers/artists-list.coffee
index ed49c38d..b182fa60 100644
--- a/resources/assets/scripts/app/controllers/artists-list.coffee
+++ b/resources/assets/scripts/app/controllers/artists-list.coffee
@@ -20,7 +20,7 @@ window.pfm.preloaders['artists-list'] = [
artists.fetchList($state.params.page, true)
]
-angular.module('ponyfm').controller "artists-list", [
+module.exports = angular.module('ponyfm').controller "artists-list", [
'$scope', 'artists', '$state'
($scope, artists, $state) ->
artists.fetchList($state.params.page).done (list) ->
diff --git a/resources/assets/scripts/app/controllers/artists.coffee b/resources/assets/scripts/app/controllers/artists.coffee
index 2f4c94d4..7e32b9e8 100644
--- a/resources/assets/scripts/app/controllers/artists.coffee
+++ b/resources/assets/scripts/app/controllers/artists.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').controller "artists", [
+module.exports = angular.module('ponyfm').controller "artists", [
'$scope', 'artists', '$state'
($scope, artists, $state) ->
diff --git a/resources/assets/scripts/app/controllers/credits.coffee b/resources/assets/scripts/app/controllers/credits.coffee
index 4625d7f2..af58e2a6 100644
--- a/resources/assets/scripts/app/controllers/credits.coffee
+++ b/resources/assets/scripts/app/controllers/credits.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').controller "credits", [
+module.exports = angular.module('ponyfm').controller "credits", [
'$scope', 'dialog',
($scope, dialog) ->
$scope.close = () -> dialog.close(null)
diff --git a/resources/assets/scripts/app/controllers/dashboard.coffee b/resources/assets/scripts/app/controllers/dashboard.coffee
index 6b1e9542..e4f8246c 100644
--- a/resources/assets/scripts/app/controllers/dashboard.coffee
+++ b/resources/assets/scripts/app/controllers/dashboard.coffee
@@ -19,7 +19,7 @@ window.pfm.preloaders['dashboard'] = [
(dashboard) -> dashboard.refresh(true)
]
-angular.module('ponyfm').controller "dashboard", [
+module.exports = angular.module('ponyfm').controller "dashboard", [
'$scope', 'dashboard', 'auth', '$http'
($scope, dashboard, auth, $http) ->
$scope.recentTracks = null
diff --git a/resources/assets/scripts/app/controllers/favourites-albums.coffee b/resources/assets/scripts/app/controllers/favourites-albums.coffee
index cf59d5d9..3403b5da 100644
--- a/resources/assets/scripts/app/controllers/favourites-albums.coffee
+++ b/resources/assets/scripts/app/controllers/favourites-albums.coffee
@@ -20,7 +20,7 @@ window.pfm.preloaders['favourites-albums'] = [
favourites.fetchAlbums(true)
]
-angular.module('ponyfm').controller "favourites-albums", [
+module.exports = angular.module('ponyfm').controller "favourites-albums", [
'$scope', 'favourites'
($scope, favourites) ->
favourites.fetchAlbums().done (res) ->
diff --git a/resources/assets/scripts/app/controllers/favourites-playlists.coffee b/resources/assets/scripts/app/controllers/favourites-playlists.coffee
index faac9e1d..b74de9bc 100644
--- a/resources/assets/scripts/app/controllers/favourites-playlists.coffee
+++ b/resources/assets/scripts/app/controllers/favourites-playlists.coffee
@@ -20,7 +20,7 @@ window.pfm.preloaders['favourites-playlists'] = [
favourites.fetchPlaylists(true)
]
-angular.module('ponyfm').controller "favourites-playlists", [
+module.exports = angular.module('ponyfm').controller "favourites-playlists", [
'$scope', 'favourites'
($scope, favourites) ->
favourites.fetchPlaylists().done (res) ->
diff --git a/resources/assets/scripts/app/controllers/favourites-tracks.coffee b/resources/assets/scripts/app/controllers/favourites-tracks.coffee
index 6e5af332..7c229ed2 100644
--- a/resources/assets/scripts/app/controllers/favourites-tracks.coffee
+++ b/resources/assets/scripts/app/controllers/favourites-tracks.coffee
@@ -20,7 +20,7 @@ window.pfm.preloaders['favourites-tracks'] = [
favourites.fetchTracks(true)
]
-angular.module('ponyfm').controller "favourites-tracks", [
+module.exports = angular.module('ponyfm').controller "favourites-tracks", [
'$scope', 'favourites'
($scope, favourites) ->
favourites.fetchTracks().done (res) ->
diff --git a/resources/assets/scripts/app/controllers/home.coffee b/resources/assets/scripts/app/controllers/home.coffee
index 54d9e3c1..31367d43 100644
--- a/resources/assets/scripts/app/controllers/home.coffee
+++ b/resources/assets/scripts/app/controllers/home.coffee
@@ -19,7 +19,7 @@ window.pfm.preloaders['home'] = [
(dashboard) -> dashboard.refresh(true)
]
-angular.module('ponyfm').controller "home", [
+module.exports = angular.module('ponyfm').controller "home", [
'$scope', 'dashboard'
($scope, dashboard) ->
$scope.recentTracks = null
diff --git a/resources/assets/scripts/app/controllers/login.coffee b/resources/assets/scripts/app/controllers/login.coffee
index 33c47a88..ccf6d636 100644
--- a/resources/assets/scripts/app/controllers/login.coffee
+++ b/resources/assets/scripts/app/controllers/login.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').controller "login", [
+module.exports = angular.module('ponyfm').controller "login", [
'$scope', 'auth'
($scope, auth) ->
diff --git a/resources/assets/scripts/app/controllers/playlist-form.coffee b/resources/assets/scripts/app/controllers/playlist-form.coffee
index b588c7da..f9ad57bb 100644
--- a/resources/assets/scripts/app/controllers/playlist-form.coffee
+++ b/resources/assets/scripts/app/controllers/playlist-form.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').controller "playlist-form", [
+module.exports = angular.module('ponyfm').controller "playlist-form", [
'$scope', 'dialog', 'playlists', 'playlist'
($scope, dialog, playlists, playlist) ->
$scope.isLoading = false
diff --git a/resources/assets/scripts/app/controllers/playlist.coffee b/resources/assets/scripts/app/controllers/playlist.coffee
index f522d8f5..d14cc496 100644
--- a/resources/assets/scripts/app/controllers/playlist.coffee
+++ b/resources/assets/scripts/app/controllers/playlist.coffee
@@ -20,7 +20,7 @@ window.pfm.preloaders['playlist'] = [
playlists.fetch $state.params.id, true
]
-angular.module('ponyfm').controller 'playlist', [
+module.exports = angular.module('ponyfm').controller 'playlist', [
'$scope', '$rootScope', '$state', 'playlists', '$dialog', 'download-cached', '$window', '$timeout'
($scope, $rootScope, $state, playlists, $dialog, cachedPlaylist, $window, $timeout) ->
playlist = null
diff --git a/resources/assets/scripts/app/controllers/playlists-list.coffee b/resources/assets/scripts/app/controllers/playlists-list.coffee
index 7727aa84..98e34821 100644
--- a/resources/assets/scripts/app/controllers/playlists-list.coffee
+++ b/resources/assets/scripts/app/controllers/playlists-list.coffee
@@ -20,7 +20,7 @@ window.pfm.preloaders['playlists-list'] = [
playlists.fetchList($state.params.page, true)
]
-angular.module('ponyfm').controller "playlists-list", [
+module.exports = angular.module('ponyfm').controller "playlists-list", [
'$scope', 'playlists', '$state',
($scope, playlists, $state) ->
playlists.fetchList($state.params.page).done (searchResults) ->
diff --git a/resources/assets/scripts/app/controllers/playlists.coffee b/resources/assets/scripts/app/controllers/playlists.coffee
index 5a5416bd..b1146ff2 100644
--- a/resources/assets/scripts/app/controllers/playlists.coffee
+++ b/resources/assets/scripts/app/controllers/playlists.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').controller "playlists", [
+module.exports = angular.module('ponyfm').controller "playlists", [
'$scope', 'playlists', '$state'
($scope, playlists, $state) ->
diff --git a/resources/assets/scripts/app/controllers/sidebar.coffee b/resources/assets/scripts/app/controllers/sidebar.coffee
index a8b53407..5943afc2 100644
--- a/resources/assets/scripts/app/controllers/sidebar.coffee
+++ b/resources/assets/scripts/app/controllers/sidebar.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').controller "sidebar", [
+module.exports = angular.module('ponyfm').controller "sidebar", [
'$scope', '$dialog', 'playlists'
($scope, $dialog, playlists) ->
$scope.playlists = playlists.pinnedPlaylists
diff --git a/resources/assets/scripts/app/controllers/track-edit.coffee b/resources/assets/scripts/app/controllers/track-edit.coffee
index 302536b9..ef67afb7 100644
--- a/resources/assets/scripts/app/controllers/track-edit.coffee
+++ b/resources/assets/scripts/app/controllers/track-edit.coffee
@@ -15,7 +15,7 @@
# along with this program. If not, see .
-angular.module('ponyfm').controller "track-edit", [
+module.exports = angular.module('ponyfm').controller "track-edit", [
'$scope', '$state'
($scope, $state) ->
# All the fun stuff happens in the pfmTrackEditor directive.
diff --git a/resources/assets/scripts/app/controllers/track-show.coffee b/resources/assets/scripts/app/controllers/track-show.coffee
index c140bdbd..4a9d9ab8 100644
--- a/resources/assets/scripts/app/controllers/track-show.coffee
+++ b/resources/assets/scripts/app/controllers/track-show.coffee
@@ -20,7 +20,7 @@ window.pfm.preloaders['track-show'] = [
$.when.all [tracks.fetch $state.params.id, playlists.refreshOwned(true)]
]
-angular.module('ponyfm').controller "track-show", [
+module.exports = angular.module('ponyfm').controller "track-show", [
'$scope', 'tracks', '$state', 'playlists', 'auth', 'favourites', '$dialog'
($scope, tracks, $state, playlists, auth, favourites, $dialog) ->
]
diff --git a/resources/assets/scripts/app/controllers/track.coffee b/resources/assets/scripts/app/controllers/track.coffee
index 089cb823..84787b37 100644
--- a/resources/assets/scripts/app/controllers/track.coffee
+++ b/resources/assets/scripts/app/controllers/track.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').controller "track", [
+module.exports = angular.module('ponyfm').controller "track", [
'$scope', '$rootScope', 'tracks', '$state', 'playlists', 'auth', 'favourites', '$dialog', 'download-cached', '$window', '$timeout'
($scope, $rootScope, tracks, $state, playlists, auth, favourites, $dialog, cachedTrack, $window, $timeout) ->
$scope.track
diff --git a/resources/assets/scripts/app/controllers/tracks-list.coffee b/resources/assets/scripts/app/controllers/tracks-list.coffee
index 357704f8..20fd6742 100644
--- a/resources/assets/scripts/app/controllers/tracks-list.coffee
+++ b/resources/assets/scripts/app/controllers/tracks-list.coffee
@@ -25,7 +25,7 @@ window.pfm.preloaders['tracks-list'] = [
)
]
-angular.module('ponyfm').controller "tracks-list", [
+module.exports = angular.module('ponyfm').controller "tracks-list", [
'$scope', 'tracks', '$state',
($scope, tracks, $state) ->
tracks.mainQuery.fetch().done (searchResults) ->
diff --git a/resources/assets/scripts/app/controllers/tracks.coffee b/resources/assets/scripts/app/controllers/tracks.coffee
index 33dbc0d4..308a1697 100644
--- a/resources/assets/scripts/app/controllers/tracks.coffee
+++ b/resources/assets/scripts/app/controllers/tracks.coffee
@@ -20,7 +20,7 @@ window.pfm.preloaders['tracks'] = [
tracks.loadFilters()
]
-angular.module('ponyfm').controller "tracks", [
+module.exports = angular.module('ponyfm').controller "tracks", [
'$scope', 'tracks', '$state', 'focus'
($scope, tracks, $state, focus) ->
$scope.recentTracks = null
diff --git a/resources/assets/scripts/app/controllers/uploader.coffee b/resources/assets/scripts/app/controllers/uploader.coffee
index 51ce3515..0d05dd40 100644
--- a/resources/assets/scripts/app/controllers/uploader.coffee
+++ b/resources/assets/scripts/app/controllers/uploader.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').controller "uploader", [
+module.exports = angular.module('ponyfm').controller "uploader", [
'$scope', 'auth', 'upload', '$state'
($scope, auth, upload, $state) ->
$scope.data = upload
diff --git a/resources/assets/scripts/app/directives/albums-list.coffee b/resources/assets/scripts/app/directives/albums-list.coffee
index c066d115..b7e341c0 100644
--- a/resources/assets/scripts/app/directives/albums-list.coffee
+++ b/resources/assets/scripts/app/directives/albums-list.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmAlbumsList', () ->
+module.exports = angular.module('ponyfm').directive 'pfmAlbumsList', () ->
restrict: 'E'
replace: true
templateUrl: '/templates/directives/albums-list.html'
diff --git a/resources/assets/scripts/app/directives/colorbox.coffee b/resources/assets/scripts/app/directives/colorbox.coffee
index 99571b3b..a75a97e7 100644
--- a/resources/assets/scripts/app/directives/colorbox.coffee
+++ b/resources/assets/scripts/app/directives/colorbox.coffee
@@ -16,7 +16,7 @@
# Based on http://stackoverflow.com/questions/14641791/how-to-use-colorbox-with-angular-js
-angular.module('ponyfm').directive 'colorbox', ->
+module.exports = angular.module('ponyfm').directive 'colorbox', ->
restrict: 'AC'
link: (scope, element, attrs) ->
$(element).colorbox({maxWidth:'90%', maxHeight:'90%'})
diff --git a/resources/assets/scripts/app/directives/comments.coffee b/resources/assets/scripts/app/directives/comments.coffee
index d84ada50..8e1c89bf 100644
--- a/resources/assets/scripts/app/directives/comments.coffee
+++ b/resources/assets/scripts/app/directives/comments.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmComments', () ->
+module.exports = angular.module('ponyfm').directive 'pfmComments', () ->
restrict: 'E'
templateUrl: '/templates/directives/comments.html'
scope:
diff --git a/resources/assets/scripts/app/directives/eat-click.coffee b/resources/assets/scripts/app/directives/eat-click.coffee
index ef69c5ef..e4405034 100644
--- a/resources/assets/scripts/app/directives/eat-click.coffee
+++ b/resources/assets/scripts/app/directives/eat-click.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmEatClick', () ->
+module.exports = angular.module('ponyfm').directive 'pfmEatClick', () ->
(scope, element) ->
$(element).click (e) ->
e.preventDefault()
diff --git a/resources/assets/scripts/app/directives/favouriteButton.coffee b/resources/assets/scripts/app/directives/favouriteButton.coffee
index 3e8e879e..d033cd18 100644
--- a/resources/assets/scripts/app/directives/favouriteButton.coffee
+++ b/resources/assets/scripts/app/directives/favouriteButton.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmFavouriteButton', () ->
+module.exports = angular.module('ponyfm').directive 'pfmFavouriteButton', () ->
restrict: 'E'
templateUrl: '/templates/directives/favourite-button.html'
scope:
diff --git a/resources/assets/scripts/app/directives/image-upload.coffee b/resources/assets/scripts/app/directives/image-upload.coffee
index 923165f8..71760713 100644
--- a/resources/assets/scripts/app/directives/image-upload.coffee
+++ b/resources/assets/scripts/app/directives/image-upload.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmImageUpload', () ->
+module.exports = angular.module('ponyfm').directive 'pfmImageUpload', () ->
$image = null
$uploader = null
diff --git a/resources/assets/scripts/app/directives/on-enter.coffee b/resources/assets/scripts/app/directives/on-enter.coffee
index 5e2baaf1..7a6bfab5 100644
--- a/resources/assets/scripts/app/directives/on-enter.coffee
+++ b/resources/assets/scripts/app/directives/on-enter.coffee
@@ -17,7 +17,7 @@
# This directive calls the given function when Enter is pressed in a
# standalone input field.
-angular.module('ponyfm').directive 'pfmOnEnter', () ->
+module.exports = angular.module('ponyfm').directive 'pfmOnEnter', () ->
(scope, element, attrs) ->
element.bind("keyup", (event) ->
if (event.which is 13)
diff --git a/resources/assets/scripts/app/directives/player.coffee b/resources/assets/scripts/app/directives/player.coffee
index 7f924555..dc1fd45b 100644
--- a/resources/assets/scripts/app/directives/player.coffee
+++ b/resources/assets/scripts/app/directives/player.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmPlayer', () ->
+module.exports = angular.module('ponyfm').directive 'pfmPlayer', () ->
$element = null
restrict: 'E'
diff --git a/resources/assets/scripts/app/directives/playlists-list.coffee b/resources/assets/scripts/app/directives/playlists-list.coffee
index 54b3464d..49269646 100644
--- a/resources/assets/scripts/app/directives/playlists-list.coffee
+++ b/resources/assets/scripts/app/directives/playlists-list.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmPlaylistsList', () ->
+module.exports = angular.module('ponyfm').directive 'pfmPlaylistsList', () ->
restrict: 'E'
replace: true
templateUrl: '/templates/directives/playlists-list.html'
diff --git a/resources/assets/scripts/app/directives/popup.coffee b/resources/assets/scripts/app/directives/popup.coffee
index d40cc307..e824542e 100644
--- a/resources/assets/scripts/app/directives/popup.coffee
+++ b/resources/assets/scripts/app/directives/popup.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmPopup', () ->
+module.exports = angular.module('ponyfm').directive 'pfmPopup', () ->
(scope, element, attrs) ->
align = 'left'
elementId = attrs.pfmPopup
diff --git a/resources/assets/scripts/app/directives/progress-bar.coffee b/resources/assets/scripts/app/directives/progress-bar.coffee
index 3296e783..38e91db5 100644
--- a/resources/assets/scripts/app/directives/progress-bar.coffee
+++ b/resources/assets/scripts/app/directives/progress-bar.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmProgressBar', () ->
+module.exports = angular.module('ponyfm').directive 'pfmProgressBar', () ->
(scope, element, attrs) ->
scope.$watch attrs.pfmProgressBar, (val) ->
return if !val?
diff --git a/resources/assets/scripts/app/directives/scroll-recorder.coffee b/resources/assets/scripts/app/directives/scroll-recorder.coffee
index d24b61e9..a9c0160f 100644
--- a/resources/assets/scripts/app/directives/scroll-recorder.coffee
+++ b/resources/assets/scripts/app/directives/scroll-recorder.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmScrollRecorder', () ->
+module.exports = angular.module('ponyfm').directive 'pfmScrollRecorder', () ->
(scope, element, attrs) ->
timeout = null
onScroll = null
diff --git a/resources/assets/scripts/app/directives/search.coffee b/resources/assets/scripts/app/directives/search.coffee
index c08dddc3..35782ccd 100644
--- a/resources/assets/scripts/app/directives/search.coffee
+++ b/resources/assets/scripts/app/directives/search.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmSearch', () ->
+module.exports = angular.module('ponyfm').directive 'pfmSearch', () ->
restrict: 'E'
templateUrl: '/templates/directives/search.html'
scope:
diff --git a/resources/assets/scripts/app/directives/share-buttons.coffee b/resources/assets/scripts/app/directives/share-buttons.coffee
index e294b156..6b40f4a2 100644
--- a/resources/assets/scripts/app/directives/share-buttons.coffee
+++ b/resources/assets/scripts/app/directives/share-buttons.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmShareButtons', () ->
+module.exports = angular.module('ponyfm').directive 'pfmShareButtons', () ->
(scope, element) ->
window.setTimeout((->
Tumblr.activate_share_on_tumblr_buttons()
diff --git a/resources/assets/scripts/app/directives/src-loader.coffee b/resources/assets/scripts/app/directives/src-loader.coffee
index be1500f4..1af7956f 100644
--- a/resources/assets/scripts/app/directives/src-loader.coffee
+++ b/resources/assets/scripts/app/directives/src-loader.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmSrcLoader', () ->
+module.exports = angular.module('ponyfm').directive 'pfmSrcLoader', () ->
(scope, element, attrs) ->
size = attrs.pfmSrcSize || 'normal'
element.css {opacity: .5}
diff --git a/resources/assets/scripts/app/directives/track-editor.coffee b/resources/assets/scripts/app/directives/track-editor.coffee
index 16a00884..f41eb8a8 100644
--- a/resources/assets/scripts/app/directives/track-editor.coffee
+++ b/resources/assets/scripts/app/directives/track-editor.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmTrackEditor', () ->
+module.exports = angular.module('ponyfm').directive 'pfmTrackEditor', () ->
restrict: 'E'
templateUrl: '/templates/directives/track-editor.html'
scope:
diff --git a/resources/assets/scripts/app/directives/track-player.coffee b/resources/assets/scripts/app/directives/track-player.coffee
index e08527ec..2ef3a616 100644
--- a/resources/assets/scripts/app/directives/track-player.coffee
+++ b/resources/assets/scripts/app/directives/track-player.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmTrackPlayer', () ->
+module.exports = angular.module('ponyfm').directive 'pfmTrackPlayer', () ->
restrict: 'E'
templateUrl: '/templates/directives/track-player.html'
scope:
diff --git a/resources/assets/scripts/app/directives/tracks-list.coffee b/resources/assets/scripts/app/directives/tracks-list.coffee
index 40f9b56a..d0d665aa 100644
--- a/resources/assets/scripts/app/directives/tracks-list.coffee
+++ b/resources/assets/scripts/app/directives/tracks-list.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmTracksList', () ->
+module.exports = angular.module('ponyfm').directive 'pfmTracksList', () ->
restrict: 'E'
templateUrl: '/templates/directives/tracks-list.html'
replace: true
diff --git a/resources/assets/scripts/app/directives/uploader.coffee b/resources/assets/scripts/app/directives/uploader.coffee
index 124bf816..3b5f8002 100644
--- a/resources/assets/scripts/app/directives/uploader.coffee
+++ b/resources/assets/scripts/app/directives/uploader.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'uploader', [
+module.exports = angular.module('ponyfm').directive 'uploader', [
'upload'
(upload) -> (scope, element) ->
$dropzone = $(element)
diff --git a/resources/assets/scripts/app/directives/users-list.coffee b/resources/assets/scripts/app/directives/users-list.coffee
index 82f6e8c0..35c24e7f 100644
--- a/resources/assets/scripts/app/directives/users-list.coffee
+++ b/resources/assets/scripts/app/directives/users-list.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').directive 'pfmUsersList', () ->
+module.exports = angular.module('ponyfm').directive 'pfmUsersList', () ->
restrict: 'E'
replace: true
templateUrl: '/templates/directives/users-list.html'
diff --git a/resources/assets/scripts/app/filters/length.coffee b/resources/assets/scripts/app/filters/length.coffee
index 598e77a8..2c28e29b 100644
--- a/resources/assets/scripts/app/filters/length.coffee
+++ b/resources/assets/scripts/app/filters/length.coffee
@@ -14,6 +14,6 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').filter 'pfmLength', () ->
+module.exports = angular.module('ponyfm').filter 'pfmLength', () ->
(input) ->
input.length
diff --git a/resources/assets/scripts/app/filters/moment-from-now.coffee b/resources/assets/scripts/app/filters/moment-from-now.coffee
index f5487926..9204de2f 100644
--- a/resources/assets/scripts/app/filters/moment-from-now.coffee
+++ b/resources/assets/scripts/app/filters/moment-from-now.coffee
@@ -14,6 +14,6 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').filter 'momentFromNow', () ->
+module.exports = angular.module('ponyfm').filter 'momentFromNow', () ->
(input) ->
moment.utc(input).fromNow()
diff --git a/resources/assets/scripts/app/filters/nl2br.coffee b/resources/assets/scripts/app/filters/nl2br.coffee
index c4ff8a1b..d9cfe908 100644
--- a/resources/assets/scripts/app/filters/nl2br.coffee
+++ b/resources/assets/scripts/app/filters/nl2br.coffee
@@ -1,6 +1,6 @@
# Based on https://gist.github.com/kensnyder/49136af39457445e5982
-angular.module('ponyfm').filter 'nl2br', [
+module.exports = angular.module('ponyfm').filter 'nl2br', [
'$sanitize'
($sanitize) ->
tag = if /xhtml/i.test(document.doctype) then ' ' else ' '
@@ -8,4 +8,4 @@ angular.module('ponyfm').filter 'nl2br', [
# ngSanitize's linky filter changes \r and \n to
and
respectively
msg = (msg + '').replace(/(\r\n|\n\r|\r|\n|
|
|
|
)/g, tag + '$1')
$sanitize msg
-]
\ No newline at end of file
+]
diff --git a/resources/assets/scripts/app/filters/noHTML.coffee b/resources/assets/scripts/app/filters/noHTML.coffee
index a77eaf75..c0b27663 100644
--- a/resources/assets/scripts/app/filters/noHTML.coffee
+++ b/resources/assets/scripts/app/filters/noHTML.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').filter 'noHTML', () ->
+module.exports = angular.module('ponyfm').filter 'noHTML', () ->
(input) ->
return '' if !input
diff --git a/resources/assets/scripts/app/filters/seconds-display.coffee b/resources/assets/scripts/app/filters/seconds-display.coffee
index 0e2f8e22..3aa7278d 100644
--- a/resources/assets/scripts/app/filters/seconds-display.coffee
+++ b/resources/assets/scripts/app/filters/seconds-display.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').filter 'secondsDisplay', () ->
+module.exports = angular.module('ponyfm').filter 'secondsDisplay', () ->
(input) ->
sec_num = parseInt(input, 10)
return '00:00' if !sec_num
diff --git a/resources/assets/scripts/app/filters/trust.coffee b/resources/assets/scripts/app/filters/trust.coffee
index 8fb30e71..ec123f1a 100644
--- a/resources/assets/scripts/app/filters/trust.coffee
+++ b/resources/assets/scripts/app/filters/trust.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').filter 'trust', [
+module.exports = angular.module('ponyfm').filter 'trust', [
'$sce'
($sce) ->
(input) ->
diff --git a/resources/assets/scripts/app/services/account-albums.coffee b/resources/assets/scripts/app/services/account-albums.coffee
index 4cf93d99..bcbdad03 100644
--- a/resources/assets/scripts/app/services/account-albums.coffee
+++ b/resources/assets/scripts/app/services/account-albums.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('account-albums', [
+module.exports = angular.module('ponyfm').factory('account-albums', [
'$rootScope', '$http'
($rootScope, $http) ->
def = null
diff --git a/resources/assets/scripts/app/services/account-tracks.coffee b/resources/assets/scripts/app/services/account-tracks.coffee
index abfc21a1..86f3cb12 100644
--- a/resources/assets/scripts/app/services/account-tracks.coffee
+++ b/resources/assets/scripts/app/services/account-tracks.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('account-tracks', [
+module.exports = angular.module('ponyfm').factory('account-tracks', [
'$rootScope', '$http'
($rootScope, $http) ->
cache = {}
diff --git a/resources/assets/scripts/app/services/admin-genres.coffee b/resources/assets/scripts/app/services/admin-genres.coffee
index 0e91f94e..9bf307b7 100644
--- a/resources/assets/scripts/app/services/admin-genres.coffee
+++ b/resources/assets/scripts/app/services/admin-genres.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('admin-genres', [
+module.exports = angular.module('ponyfm').factory('admin-genres', [
'$rootScope', '$http'
($rootScope, $http) ->
def = null
diff --git a/resources/assets/scripts/app/services/albums.coffee b/resources/assets/scripts/app/services/albums.coffee
index f2be4933..dc17fb9b 100644
--- a/resources/assets/scripts/app/services/albums.coffee
+++ b/resources/assets/scripts/app/services/albums.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('albums', [
+module.exports = angular.module('ponyfm').factory('albums', [
'$rootScope', '$http'
($rootScope, $http) ->
albumPages = []
diff --git a/resources/assets/scripts/app/services/artists.coffee b/resources/assets/scripts/app/services/artists.coffee
index 442b0035..6fbbf822 100644
--- a/resources/assets/scripts/app/services/artists.coffee
+++ b/resources/assets/scripts/app/services/artists.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('artists', [
+module.exports = angular.module('ponyfm').factory('artists', [
'$rootScope', '$http'
($rootScope, $http) ->
artistPage = []
diff --git a/resources/assets/scripts/app/services/auth.coffee b/resources/assets/scripts/app/services/auth.coffee
index 1b366cae..70d390e3 100644
--- a/resources/assets/scripts/app/services/auth.coffee
+++ b/resources/assets/scripts/app/services/auth.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('auth', [
+module.exports = angular.module('ponyfm').factory('auth', [
'$rootScope'
($rootScope) ->
data: {isLogged: window.pfm.auth.isLogged, user: window.pfm.auth.user}
diff --git a/resources/assets/scripts/app/services/comments.coffee b/resources/assets/scripts/app/services/comments.coffee
index 34d944f9..8c7e1ae5 100644
--- a/resources/assets/scripts/app/services/comments.coffee
+++ b/resources/assets/scripts/app/services/comments.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('comments', [
+module.exports = angular.module('ponyfm').factory('comments', [
'$rootScope', '$http'
($rootScope, $http) ->
commentCache = []
diff --git a/resources/assets/scripts/app/services/dashboard.coffee b/resources/assets/scripts/app/services/dashboard.coffee
index 55198e02..216a9ea7 100644
--- a/resources/assets/scripts/app/services/dashboard.coffee
+++ b/resources/assets/scripts/app/services/dashboard.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('dashboard', [
+module.exports = angular.module('ponyfm').factory('dashboard', [
'$rootScope', '$http'
($rootScope, $http) ->
def = null
diff --git a/resources/assets/scripts/app/services/download-cached.coffee b/resources/assets/scripts/app/services/download-cached.coffee
index a76c311d..79afbaad 100644
--- a/resources/assets/scripts/app/services/download-cached.coffee
+++ b/resources/assets/scripts/app/services/download-cached.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('download-cached', [
+module.exports = angular.module('ponyfm').factory('download-cached', [
'$rootScope', '$http', '$log'
($rootScope, $http, $log) ->
download = (type, id, format) ->
@@ -33,4 +33,4 @@ angular.module('ponyfm').factory('download-cached', [
$http.get(url).then(encodingComplete).catch encodingFailed
{download: download}
-])
\ No newline at end of file
+])
diff --git a/resources/assets/scripts/app/services/favourites.coffee b/resources/assets/scripts/app/services/favourites.coffee
index a5ca3471..b9e35886 100644
--- a/resources/assets/scripts/app/services/favourites.coffee
+++ b/resources/assets/scripts/app/services/favourites.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('favourites', [
+module.exports = angular.module('ponyfm').factory('favourites', [
'$rootScope', '$http'
($rootScope, $http) ->
tracksDef = null
diff --git a/resources/assets/scripts/app/services/focus.coffee b/resources/assets/scripts/app/services/focus.coffee
index 63033c38..1f1b6a4c 100644
--- a/resources/assets/scripts/app/services/focus.coffee
+++ b/resources/assets/scripts/app/services/focus.coffee
@@ -19,7 +19,7 @@
# using a jQuery selector.
#
# Based on: https://stackoverflow.com/a/25597540/3225811
-angular.module('ponyfm').factory('focus', ['$timeout', '$window', ($timeout, $window) ->
+module.exports = angular.module('ponyfm').factory('focus', ['$timeout', '$window', ($timeout, $window) ->
(selector) ->
$timeout () ->
element = $window.jQuery("#{selector}")
diff --git a/resources/assets/scripts/app/services/follow.coffee b/resources/assets/scripts/app/services/follow.coffee
index d26239d3..c7beface 100644
--- a/resources/assets/scripts/app/services/follow.coffee
+++ b/resources/assets/scripts/app/services/follow.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('follow', [
+module.exports = angular.module('ponyfm').factory('follow', [
'$rootScope', '$http'
($rootScope, $http) ->
self =
diff --git a/resources/assets/scripts/app/services/images.coffee b/resources/assets/scripts/app/services/images.coffee
index 6fa6d646..390767b0 100644
--- a/resources/assets/scripts/app/services/images.coffee
+++ b/resources/assets/scripts/app/services/images.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('images', [
+module.exports = angular.module('ponyfm').factory('images', [
'$rootScope'
($rootScope) ->
def = null
diff --git a/resources/assets/scripts/app/services/lightbox.coffee b/resources/assets/scripts/app/services/lightbox.coffee
index 081608c6..c3306d58 100644
--- a/resources/assets/scripts/app/services/lightbox.coffee
+++ b/resources/assets/scripts/app/services/lightbox.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('lightbox', [
+module.exports = angular.module('ponyfm').factory('lightbox', [
() ->
openDataUrl: (src) ->
$.colorbox
diff --git a/resources/assets/scripts/app/services/player.coffee b/resources/assets/scripts/app/services/player.coffee
index f3d42afc..20d25070 100644
--- a/resources/assets/scripts/app/services/player.coffee
+++ b/resources/assets/scripts/app/services/player.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('player', [
+module.exports = angular.module('ponyfm').factory('player', [
'$rootScope'
($rootScope) ->
readyDef = new $.Deferred()
diff --git a/resources/assets/scripts/app/services/playlists.coffee b/resources/assets/scripts/app/services/playlists.coffee
index afbd14ab..b1d137cb 100644
--- a/resources/assets/scripts/app/services/playlists.coffee
+++ b/resources/assets/scripts/app/services/playlists.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('playlists', [
+module.exports = angular.module('ponyfm').factory('playlists', [
'$rootScope', '$state', '$http', 'auth'
($rootScope, $state, $http, auth) ->
playlistDef = null
diff --git a/resources/assets/scripts/app/services/search.coffee b/resources/assets/scripts/app/services/search.coffee
index 8529c763..6dce7c53 100644
--- a/resources/assets/scripts/app/services/search.coffee
+++ b/resources/assets/scripts/app/services/search.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('search', [
+module.exports = angular.module('ponyfm').factory('search', [
'$http'
($http) ->
diff --git a/resources/assets/scripts/app/services/taxonomies.coffee b/resources/assets/scripts/app/services/taxonomies.coffee
index 5f97203d..bc16d6c1 100644
--- a/resources/assets/scripts/app/services/taxonomies.coffee
+++ b/resources/assets/scripts/app/services/taxonomies.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('taxonomies', [
+module.exports = angular.module('ponyfm').factory('taxonomies', [
'$rootScope', '$http'
($rootScope, $http) ->
def = null
diff --git a/resources/assets/scripts/app/services/tracks.coffee b/resources/assets/scripts/app/services/tracks.coffee
index 5f9964e5..2d19333f 100644
--- a/resources/assets/scripts/app/services/tracks.coffee
+++ b/resources/assets/scripts/app/services/tracks.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('tracks', [
+module.exports = angular.module('ponyfm').factory('tracks', [
'$rootScope', '$http', 'taxonomies'
($rootScope, $http, taxonomies) ->
filterDef = null
diff --git a/resources/assets/scripts/app/services/upload.coffee b/resources/assets/scripts/app/services/upload.coffee
index a9657fbd..58aa8ac3 100644
--- a/resources/assets/scripts/app/services/upload.coffee
+++ b/resources/assets/scripts/app/services/upload.coffee
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-angular.module('ponyfm').factory('upload', [
+module.exports = angular.module('ponyfm').factory('upload', [
'$rootScope', '$http', '$timeout', 'account-tracks'
($rootScope, $http, $timeout, accountTracks) ->
self =
diff --git a/resources/assets/scripts/base/angular.js b/resources/assets/scripts/base/angular.js
deleted file mode 100644
index 05cae2c6..00000000
--- a/resources/assets/scripts/base/angular.js
+++ /dev/null
@@ -1,30428 +0,0 @@
-/**
- * @license AngularJS v1.5.0
- * (c) 2010-2016 Google, Inc. http://angularjs.org
- * License: MIT
- */
-(function(window, document, undefined) {'use strict';
-
-/**
- * @description
- *
- * This object provides a utility for producing rich Error messages within
- * Angular. 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;
- return function() {
- var SKIP_INDEXES = 2;
-
- var templateArgs = arguments,
- code = templateArgs[0],
- message = '[' + (module ? module + ':' : '') + code + '] ',
- template = templateArgs[1],
- paramPrefix, i;
-
- message += template.replace(/\{\d+\}/g, function(match) {
- var index = +match.slice(1, -1),
- shiftedIndex = index + SKIP_INDEXES;
-
- if (shiftedIndex < templateArgs.length) {
- return toDebugString(templateArgs[shiftedIndex]);
- }
-
- return match;
- });
-
- message += '\nhttp://errors.angularjs.org/1.5.0/' +
- (module ? module + '/' : '') + code;
-
- for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
- message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
- encodeURIComponent(toDebugString(templateArgs[i]));
- }
-
- return new ErrorConstructor(message);
- };
-}
-
-/* We need to tell jshint what variables are being exported */
-/* global angular: true,
- msie: true,
- jqLite: true,
- jQuery: true,
- slice: true,
- splice: true,
- push: true,
- toString: true,
- ngMinErr: true,
- angularModule: true,
- uid: true,
- REGEX_STRING_REGEXP: true,
- VALIDITY_STATE_PROPERTY: true,
-
- lowercase: true,
- uppercase: true,
- manualLowercase: true,
- manualUppercase: true,
- nodeName_: true,
- isArrayLike: true,
- forEach: true,
- forEachSorted: true,
- reverseParams: true,
- nextUid: true,
- setHashKey: true,
- extend: true,
- toInt: true,
- inherit: true,
- merge: true,
- noop: true,
- identity: true,
- valueFn: true,
- isUndefined: true,
- isDefined: true,
- isObject: true,
- isBlankObject: true,
- isString: true,
- isNumber: true,
- isDate: true,
- isArray: true,
- isFunction: true,
- isRegExp: true,
- isWindow: true,
- isScope: true,
- isFile: true,
- isFormData: true,
- isBlob: true,
- isBoolean: true,
- isPromiseLike: true,
- trim: true,
- escapeForRegexp: true,
- isElement: true,
- makeMap: true,
- includes: true,
- arrayRemove: true,
- copy: true,
- shallowCopy: true,
- equals: true,
- csp: true,
- jq: true,
- concat: true,
- sliceArgs: true,
- bind: true,
- toJsonReplacer: true,
- toJson: true,
- fromJson: true,
- convertTimezoneToLocal: true,
- timezoneToOffset: true,
- startingTag: true,
- tryDecodeURIComponent: true,
- parseKeyValue: true,
- toKeyValue: true,
- encodeUriSegment: true,
- encodeUriQuery: true,
- angularInit: true,
- bootstrap: true,
- getTestability: true,
- snake_case: true,
- bindJQuery: true,
- assertArg: true,
- assertArgFn: true,
- assertNotHasOwnProperty: true,
- getter: true,
- getBlockNodes: true,
- hasOwnProperty: true,
- createMap: true,
-
- NODE_TYPE_ELEMENT: true,
- NODE_TYPE_ATTRIBUTE: true,
- NODE_TYPE_TEXT: true,
- NODE_TYPE_COMMENT: true,
- NODE_TYPE_DOCUMENT: true,
- NODE_TYPE_DOCUMENT_FRAGMENT: true,
-*/
-
-////////////////////////////////////
-
-/**
- * @ngdoc module
- * @name ng
- * @module ng
- * @description
- *
- * # ng (core module)
- * The ng module is loaded by default when an AngularJS application is started. The module itself
- * contains the essential components for an AngularJS application to function. The table below
- * lists a high level breakdown of each of the services/factories, filters, directives and testing
- * components available within this core module.
- *
- *
- */
-
-var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
-
-// The name of a form control's ValidityState property.
-// This is used so that it's possible for internal tests to create mock ValidityStates.
-var VALIDITY_STATE_PROPERTY = 'validity';
-
-var hasOwnProperty = Object.prototype.hasOwnProperty;
-
-var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
-var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
-
-
-var manualLowercase = function(s) {
- /* jshint bitwise: false */
- return isString(s)
- ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
- : s;
-};
-var manualUppercase = function(s) {
- /* jshint bitwise: false */
- return isString(s)
- ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
- : s;
-};
-
-
-// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
-// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
-// with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387
-if ('i' !== 'I'.toLowerCase()) {
- lowercase = manualLowercase;
- uppercase = manualUppercase;
-}
-
-
-var
- msie, // holds major version number for IE, or NaN if UA is not IE.
- jqLite, // delay binding since jQuery could be loaded after us.
- jQuery, // delay binding
- slice = [].slice,
- splice = [].splice,
- push = [].push,
- toString = Object.prototype.toString,
- getPrototypeOf = Object.getPrototypeOf,
- ngMinErr = minErr('ng'),
-
- /** @name angular */
- angular = window.angular || (window.angular = {}),
- angularModule,
- uid = 0;
-
-/**
- * documentMode is an IE-only property
- * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
- */
-msie = document.documentMode;
-
-
-/**
- * @private
- * @param {*} obj
- * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
- * String ...)
- */
-function isArrayLike(obj) {
-
- // `null`, `undefined` and `window` are not array-like
- if (obj == null || isWindow(obj)) return false;
-
- // arrays, strings and jQuery/jqLite objects are array like
- // * jqLite is either the jQuery or jqLite constructor function
- // * we have to check the existence of jqLite first as this method is called
- // via the forEach method when constructing the jqLite object in the first place
- if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
-
- // Support: iOS 8.2 (not reproducible in simulator)
- // "length" in obj used to prevent JIT error (gh-11508)
- var length = "length" in Object(obj) && obj.length;
-
- // NodeList objects (with `item` method) and
- // other objects with suitable length characteristics are array-like
- return isNumber(length) &&
- (length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item == 'function');
-
-}
-
-/**
- * @ngdoc function
- * @name angular.forEach
- * @module ng
- * @kind function
- *
- * @description
- * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
- * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
- * is the value of an object property or an array element, `key` is the object property key or
- * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
- *
- * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
- * using the `hasOwnProperty` method.
- *
- * Unlike ES262's
- * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
- * Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
- * return the value provided.
- *
- ```js
- var values = {name: 'misko', gender: 'male'};
- var log = [];
- angular.forEach(values, function(value, key) {
- this.push(key + ': ' + value);
- }, log);
- expect(log).toEqual(['name: misko', 'gender: male']);
- ```
- *
- * @param {Object|Array} obj Object to iterate over.
- * @param {Function} iterator Iterator function.
- * @param {Object=} context Object to become context (`this`) for the iterator function.
- * @returns {Object|Array} Reference to `obj`.
- */
-
-function forEach(obj, iterator, context) {
- var key, length;
- if (obj) {
- if (isFunction(obj)) {
- for (key in obj) {
- // Need to check if hasOwnProperty exists,
- // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
- if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
- iterator.call(context, obj[key], key, obj);
- }
- }
- } else if (isArray(obj) || isArrayLike(obj)) {
- var isPrimitive = typeof obj !== 'object';
- for (key = 0, length = obj.length; key < length; key++) {
- if (isPrimitive || key in obj) {
- iterator.call(context, obj[key], key, obj);
- }
- }
- } else if (obj.forEach && obj.forEach !== forEach) {
- obj.forEach(iterator, context, obj);
- } else if (isBlankObject(obj)) {
- // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
- for (key in obj) {
- iterator.call(context, obj[key], key, obj);
- }
- } else if (typeof obj.hasOwnProperty === 'function') {
- // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
- for (key in obj) {
- if (obj.hasOwnProperty(key)) {
- iterator.call(context, obj[key], key, obj);
- }
- }
- } else {
- // Slow path for objects which do not have a method `hasOwnProperty`
- for (key in obj) {
- if (hasOwnProperty.call(obj, key)) {
- iterator.call(context, obj[key], key, obj);
- }
- }
- }
- }
- return obj;
-}
-
-function forEachSorted(obj, iterator, context) {
- var keys = Object.keys(obj).sort();
- for (var i = 0; i < keys.length; i++) {
- iterator.call(context, obj[keys[i]], keys[i]);
- }
- return keys;
-}
-
-
-/**
- * when using forEach the params are value, key, but it is often useful to have key, value.
- * @param {function(string, *)} iteratorFn
- * @returns {function(*, string)}
- */
-function reverseParams(iteratorFn) {
- return function(value, key) {iteratorFn(key, value);};
-}
-
-/**
- * A consistent way of creating unique IDs in angular.
- *
- * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
- * we hit number precision issues in JavaScript.
- *
- * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
- *
- * @returns {number} an unique alpha-numeric string
- */
-function nextUid() {
- return ++uid;
-}
-
-
-/**
- * Set or clear the hashkey for an object.
- * @param obj object
- * @param h the hashkey (!truthy to delete the hashkey)
- */
-function setHashKey(obj, h) {
- if (h) {
- obj.$$hashKey = h;
- } else {
- delete obj.$$hashKey;
- }
-}
-
-
-function baseExtend(dst, objs, deep) {
- var h = dst.$$hashKey;
-
- for (var i = 0, ii = objs.length; i < ii; ++i) {
- var obj = objs[i];
- if (!isObject(obj) && !isFunction(obj)) continue;
- var keys = Object.keys(obj);
- for (var j = 0, jj = keys.length; j < jj; j++) {
- var key = keys[j];
- var src = obj[key];
-
- if (deep && isObject(src)) {
- if (isDate(src)) {
- dst[key] = new Date(src.valueOf());
- } else if (isRegExp(src)) {
- dst[key] = new RegExp(src);
- } else if (src.nodeName) {
- dst[key] = src.cloneNode(true);
- } else if (isElement(src)) {
- dst[key] = src.clone();
- } else {
- if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
- baseExtend(dst[key], [src], true);
- }
- } else {
- dst[key] = src;
- }
- }
- }
-
- setHashKey(dst, h);
- return dst;
-}
-
-/**
- * @ngdoc function
- * @name angular.extend
- * @module ng
- * @kind function
- *
- * @description
- * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
- * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
- * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
- *
- * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
- * {@link angular.merge} for this.
- *
- * @param {Object} dst Destination object.
- * @param {...Object} src Source object(s).
- * @returns {Object} Reference to `dst`.
- */
-function extend(dst) {
- return baseExtend(dst, slice.call(arguments, 1), false);
-}
-
-
-/**
-* @ngdoc function
-* @name angular.merge
-* @module ng
-* @kind function
-*
-* @description
-* Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
-* to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
-* by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
-*
-* Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
-* objects, performing a deep copy.
-*
-* @param {Object} dst Destination object.
-* @param {...Object} src Source object(s).
-* @returns {Object} Reference to `dst`.
-*/
-function merge(dst) {
- return baseExtend(dst, slice.call(arguments, 1), true);
-}
-
-
-
-function toInt(str) {
- return parseInt(str, 10);
-}
-
-
-function inherit(parent, extra) {
- return extend(Object.create(parent), extra);
-}
-
-/**
- * @ngdoc function
- * @name angular.noop
- * @module ng
- * @kind function
- *
- * @description
- * A function that performs no operations. This function can be useful when writing code in the
- * functional style.
- ```js
- function foo(callback) {
- var result = calculateResult();
- (callback || angular.noop)(result);
- }
- ```
- */
-function noop() {}
-noop.$inject = [];
-
-
-/**
- * @ngdoc function
- * @name angular.identity
- * @module ng
- * @kind function
- *
- * @description
- * A function that returns its first argument. This function is useful when writing code in the
- * functional style.
- *
- ```js
- function transformer(transformationFn, value) {
- return (transformationFn || angular.identity)(value);
- };
- ```
- * @param {*} value to be returned.
- * @returns {*} the value passed in.
- */
-function identity($) {return $;}
-identity.$inject = [];
-
-
-function valueFn(value) {return function() {return value;};}
-
-function hasCustomToString(obj) {
- return isFunction(obj.toString) && obj.toString !== toString;
-}
-
-
-/**
- * @ngdoc function
- * @name angular.isUndefined
- * @module ng
- * @kind function
- *
- * @description
- * Determines if a reference is undefined.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is undefined.
- */
-function isUndefined(value) {return typeof value === 'undefined';}
-
-
-/**
- * @ngdoc function
- * @name angular.isDefined
- * @module ng
- * @kind function
- *
- * @description
- * Determines if a reference is defined.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is defined.
- */
-function isDefined(value) {return typeof value !== 'undefined';}
-
-
-/**
- * @ngdoc function
- * @name angular.isObject
- * @module ng
- * @kind function
- *
- * @description
- * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
- * considered to be objects. Note that JavaScript arrays are objects.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is an `Object` but not `null`.
- */
-function isObject(value) {
- // http://jsperf.com/isobject4
- return value !== null && typeof value === 'object';
-}
-
-
-/**
- * Determine if a value is an object with a null prototype
- *
- * @returns {boolean} True if `value` is an `Object` with a null prototype
- */
-function isBlankObject(value) {
- return value !== null && typeof value === 'object' && !getPrototypeOf(value);
-}
-
-
-/**
- * @ngdoc function
- * @name angular.isString
- * @module ng
- * @kind function
- *
- * @description
- * Determines if a reference is a `String`.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is a `String`.
- */
-function isString(value) {return typeof value === 'string';}
-
-
-/**
- * @ngdoc function
- * @name angular.isNumber
- * @module ng
- * @kind function
- *
- * @description
- * Determines if a reference is a `Number`.
- *
- * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
- *
- * If you wish to exclude these then you can use the native
- * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
- * method.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is a `Number`.
- */
-function isNumber(value) {return typeof value === 'number';}
-
-
-/**
- * @ngdoc function
- * @name angular.isDate
- * @module ng
- * @kind function
- *
- * @description
- * Determines if a value is a date.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is a `Date`.
- */
-function isDate(value) {
- return toString.call(value) === '[object Date]';
-}
-
-
-/**
- * @ngdoc function
- * @name angular.isArray
- * @module ng
- * @kind function
- *
- * @description
- * Determines if a reference is an `Array`.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is an `Array`.
- */
-var isArray = Array.isArray;
-
-/**
- * @ngdoc function
- * @name angular.isFunction
- * @module ng
- * @kind function
- *
- * @description
- * Determines if a reference is a `Function`.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is a `Function`.
- */
-function isFunction(value) {return typeof value === 'function';}
-
-
-/**
- * Determines if a value is a regular expression object.
- *
- * @private
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is a `RegExp`.
- */
-function isRegExp(value) {
- return toString.call(value) === '[object RegExp]';
-}
-
-
-/**
- * Checks if `obj` is a window object.
- *
- * @private
- * @param {*} obj Object to check
- * @returns {boolean} True if `obj` is a window obj.
- */
-function isWindow(obj) {
- return obj && obj.window === obj;
-}
-
-
-function isScope(obj) {
- return obj && obj.$evalAsync && obj.$watch;
-}
-
-
-function isFile(obj) {
- return toString.call(obj) === '[object File]';
-}
-
-
-function isFormData(obj) {
- return toString.call(obj) === '[object FormData]';
-}
-
-
-function isBlob(obj) {
- return toString.call(obj) === '[object Blob]';
-}
-
-
-function isBoolean(value) {
- return typeof value === 'boolean';
-}
-
-
-function isPromiseLike(obj) {
- return obj && isFunction(obj.then);
-}
-
-
-var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/;
-function isTypedArray(value) {
- return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
-}
-
-function isArrayBuffer(obj) {
- return toString.call(obj) === '[object ArrayBuffer]';
-}
-
-
-var trim = function(value) {
- return isString(value) ? value.trim() : value;
-};
-
-// Copied from:
-// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
-// Prereq: s is a string.
-var escapeForRegexp = function(s) {
- return s.replace(/([-()\[\]{}+?*.$\^|,:#= 0) {
- array.splice(index, 1);
- }
- return index;
-}
-
-/**
- * @ngdoc function
- * @name angular.copy
- * @module ng
- * @kind function
- *
- * @description
- * Creates a deep copy of `source`, which should be an object or an array.
- *
- * * If no destination is supplied, a copy of the object or array is created.
- * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
- * are deleted and then all elements/properties from the source are copied to it.
- * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
- * * If `source` is identical to 'destination' an exception will be thrown.
- *
- * @param {*} source The source that will be used to make a copy.
- * Can be any type, including primitives, `null`, and `undefined`.
- * @param {(Object|Array)=} destination Destination into which the source is copied. If
- * provided, must be of the same type as `source`.
- * @returns {*} The copy or updated `destination`, if `destination` was specified.
- *
- * @example
-
-
-
-
-
form = {{user | json}}
-
master = {{master | json}}
-
-
-
-
-
- */
-function copy(source, destination) {
- var stackSource = [];
- var stackDest = [];
-
- if (destination) {
- if (isTypedArray(destination) || isArrayBuffer(destination)) {
- throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
- }
- if (source === destination) {
- throw ngMinErr('cpi', "Can't copy! Source and destination are identical.");
- }
-
- // Empty the destination object
- if (isArray(destination)) {
- destination.length = 0;
- } else {
- forEach(destination, function(value, key) {
- if (key !== '$$hashKey') {
- delete destination[key];
- }
- });
- }
-
- stackSource.push(source);
- stackDest.push(destination);
- return copyRecurse(source, destination);
- }
-
- return copyElement(source);
-
- function copyRecurse(source, destination) {
- var h = destination.$$hashKey;
- var result, key;
- if (isArray(source)) {
- for (var i = 0, ii = source.length; i < ii; i++) {
- destination.push(copyElement(source[i]));
- }
- } else if (isBlankObject(source)) {
- // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
- for (key in source) {
- destination[key] = copyElement(source[key]);
- }
- } else if (source && typeof source.hasOwnProperty === 'function') {
- // Slow path, which must rely on hasOwnProperty
- for (key in source) {
- if (source.hasOwnProperty(key)) {
- destination[key] = copyElement(source[key]);
- }
- }
- } else {
- // Slowest path --- hasOwnProperty can't be called as a method
- for (key in source) {
- if (hasOwnProperty.call(source, key)) {
- destination[key] = copyElement(source[key]);
- }
- }
- }
- setHashKey(destination, h);
- return destination;
- }
-
- function copyElement(source) {
- // Simple values
- if (!isObject(source)) {
- return source;
- }
-
- // Already copied values
- var index = stackSource.indexOf(source);
- if (index !== -1) {
- return stackDest[index];
- }
-
- if (isWindow(source) || isScope(source)) {
- throw ngMinErr('cpws',
- "Can't copy! Making copies of Window or Scope instances is not supported.");
- }
-
- var needsRecurse = false;
- var destination = copyType(source);
-
- if (destination === undefined) {
- destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
- needsRecurse = true;
- }
-
- stackSource.push(source);
- stackDest.push(destination);
-
- return needsRecurse
- ? copyRecurse(source, destination)
- : destination;
- }
-
- function copyType(source) {
- switch (toString.call(source)) {
- case '[object Int8Array]':
- case '[object Int16Array]':
- case '[object Int32Array]':
- case '[object Float32Array]':
- case '[object Float64Array]':
- case '[object Uint8Array]':
- case '[object Uint8ClampedArray]':
- case '[object Uint16Array]':
- case '[object Uint32Array]':
- return new source.constructor(copyElement(source.buffer));
-
- case '[object ArrayBuffer]':
- //Support: IE10
- if (!source.slice) {
- var copied = new ArrayBuffer(source.byteLength);
- new Uint8Array(copied).set(new Uint8Array(source));
- return copied;
- }
- return source.slice(0);
-
- case '[object Boolean]':
- case '[object Number]':
- case '[object String]':
- case '[object Date]':
- return new source.constructor(source.valueOf());
-
- case '[object RegExp]':
- var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
- re.lastIndex = source.lastIndex;
- return re;
- }
-
- if (isFunction(source.cloneNode)) {
- return source.cloneNode(true);
- }
- }
-}
-
-/**
- * Creates a shallow copy of an object, an array or a primitive.
- *
- * Assumes that there are no proto properties for objects.
- */
-function shallowCopy(src, dst) {
- if (isArray(src)) {
- dst = dst || [];
-
- for (var i = 0, ii = src.length; i < ii; i++) {
- dst[i] = src[i];
- }
- } else if (isObject(src)) {
- dst = dst || {};
-
- for (var key in src) {
- if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
- dst[key] = src[key];
- }
- }
- }
-
- return dst || src;
-}
-
-
-/**
- * @ngdoc function
- * @name angular.equals
- * @module ng
- * @kind function
- *
- * @description
- * Determines if two objects or two values are equivalent. Supports value types, regular
- * expressions, arrays and objects.
- *
- * Two objects or values are considered equivalent if at least one of the following is true:
- *
- * * Both objects or values pass `===` comparison.
- * * Both objects or values are of the same type and all of their properties are equal by
- * comparing them with `angular.equals`.
- * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
- * * Both values represent the same regular expression (In JavaScript,
- * /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
- * representation matches).
- *
- * During a property comparison, properties of `function` type and properties with names
- * that begin with `$` are ignored.
- *
- * Scope and DOMWindow objects are being compared only by identify (`===`).
- *
- * @param {*} o1 Object or value to compare.
- * @param {*} o2 Object or value to compare.
- * @returns {boolean} True if arguments are equal.
- */
-function equals(o1, o2) {
- if (o1 === o2) return true;
- if (o1 === null || o2 === null) return false;
- if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
- var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
- if (t1 == t2 && t1 == 'object') {
- if (isArray(o1)) {
- if (!isArray(o2)) return false;
- if ((length = o1.length) == o2.length) {
- for (key = 0; key < length; key++) {
- if (!equals(o1[key], o2[key])) return false;
- }
- return true;
- }
- } else if (isDate(o1)) {
- if (!isDate(o2)) return false;
- return equals(o1.getTime(), o2.getTime());
- } else if (isRegExp(o1)) {
- if (!isRegExp(o2)) return false;
- return o1.toString() == o2.toString();
- } else {
- if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
- isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
- keySet = createMap();
- for (key in o1) {
- if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
- if (!equals(o1[key], o2[key])) return false;
- keySet[key] = true;
- }
- for (key in o2) {
- if (!(key in keySet) &&
- key.charAt(0) !== '$' &&
- isDefined(o2[key]) &&
- !isFunction(o2[key])) return false;
- }
- return true;
- }
- }
- return false;
-}
-
-var csp = function() {
- if (!isDefined(csp.rules)) {
-
-
- var ngCspElement = (document.querySelector('[ng-csp]') ||
- document.querySelector('[data-ng-csp]'));
-
- if (ngCspElement) {
- var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
- ngCspElement.getAttribute('data-ng-csp');
- csp.rules = {
- noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
- noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
- };
- } else {
- csp.rules = {
- noUnsafeEval: noUnsafeEval(),
- noInlineStyle: false
- };
- }
- }
-
- return csp.rules;
-
- function noUnsafeEval() {
- try {
- /* jshint -W031, -W054 */
- new Function('');
- /* jshint +W031, +W054 */
- return false;
- } catch (e) {
- return true;
- }
- }
-};
-
-/**
- * @ngdoc directive
- * @module ng
- * @name ngJq
- *
- * @element ANY
- * @param {string=} ngJq the name of the library available under `window`
- * to be used for angular.element
- * @description
- * Use this directive to force the angular.element library. This should be
- * used to force either jqLite by leaving ng-jq blank or setting the name of
- * the jquery variable under window (eg. jQuery).
- *
- * Since angular looks for this directive when it is loaded (doesn't wait for the
- * DOMContentLoaded event), it must be placed on an element that comes before the script
- * which loads angular. Also, only the first instance of `ng-jq` will be used and all
- * others ignored.
- *
- * @example
- * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
- ```html
-
-
- ...
- ...
-
- ```
- * @example
- * This example shows how to use a jQuery based library of a different name.
- * The library name must be available at the top most 'window'.
- ```html
-
-
- ...
- ...
-
- ```
- */
-var jq = function() {
- if (isDefined(jq.name_)) return jq.name_;
- var el;
- var i, ii = ngAttrPrefixes.length, prefix, name;
- for (i = 0; i < ii; ++i) {
- prefix = ngAttrPrefixes[i];
- if (el = document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
- name = el.getAttribute(prefix + 'jq');
- break;
- }
- }
-
- return (jq.name_ = name);
-};
-
-function concat(array1, array2, index) {
- return array1.concat(slice.call(array2, index));
-}
-
-function sliceArgs(args, startIndex) {
- return slice.call(args, startIndex || 0);
-}
-
-
-/* jshint -W101 */
-/**
- * @ngdoc function
- * @name angular.bind
- * @module ng
- * @kind function
- *
- * @description
- * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
- * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
- * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
- * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
- *
- * @param {Object} self Context which `fn` should be evaluated in.
- * @param {function()} fn Function to be bound.
- * @param {...*} args Optional arguments to be prebound to the `fn` function call.
- * @returns {function()} Function that wraps the `fn` with all the specified bindings.
- */
-/* jshint +W101 */
-function bind(self, fn) {
- var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
- if (isFunction(fn) && !(fn instanceof RegExp)) {
- return curryArgs.length
- ? function() {
- return arguments.length
- ? fn.apply(self, concat(curryArgs, arguments, 0))
- : fn.apply(self, curryArgs);
- }
- : function() {
- return arguments.length
- ? fn.apply(self, arguments)
- : fn.call(self);
- };
- } else {
- // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
- return fn;
- }
-}
-
-
-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 && document === value) {
- val = '$DOCUMENT';
- } else if (isScope(value)) {
- val = '$SCOPE';
- }
-
- return val;
-}
-
-
-/**
- * @ngdoc function
- * @name angular.toJson
- * @module ng
- * @kind function
- *
- * @description
- * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
- * stripped since angular uses this notation internally.
- *
- * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
- * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
- * If set to an integer, the JSON output will contain that many spaces per indentation.
- * @returns {string|undefined} JSON-ified string representing `obj`.
- */
-function toJson(obj, pretty) {
- if (isUndefined(obj)) return undefined;
- if (!isNumber(pretty)) {
- pretty = pretty ? 2 : null;
- }
- return JSON.stringify(obj, toJsonReplacer, pretty);
-}
-
-
-/**
- * @ngdoc function
- * @name angular.fromJson
- * @module ng
- * @kind function
- *
- * @description
- * Deserializes a JSON string.
- *
- * @param {string} json JSON string to deserialize.
- * @returns {Object|Array|string|number} Deserialized JSON string.
- */
-function fromJson(json) {
- return isString(json)
- ? JSON.parse(json)
- : json;
-}
-
-
-var ALL_COLONS = /:/g;
-function timezoneToOffset(timezone, fallback) {
- // IE/Edge do not "understand" colon (`:`) in timezone
- timezone = timezone.replace(ALL_COLONS, '');
- var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
- return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
-}
-
-
-function addDateMinutes(date, minutes) {
- date = new Date(date.getTime());
- date.setMinutes(date.getMinutes() + minutes);
- return date;
-}
-
-
-function convertTimezoneToLocal(date, timezone, reverse) {
- reverse = reverse ? -1 : 1;
- var dateTimezoneOffset = date.getTimezoneOffset();
- var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
- return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
-}
-
-
-/**
- * @returns {string} Returns the string representation of the element.
- */
-function startingTag(element) {
- element = jqLite(element).clone();
- try {
- // turns out IE does not let you set .html() on elements which
- // are not allowed to have children. So we just ignore it.
- element.empty();
- } catch (e) {}
- var elemHtml = jqLite('
').append(element).html();
- try {
- return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
- elemHtml.
- match(/^(<[^>]+>)/)[1].
- replace(/^<([\w\-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
- } catch (e) {
- return lowercase(elemHtml);
- }
-
-}
-
-
-/////////////////////////////////////////////////
-
-/**
- * Tries to decode the URI component without throwing an exception.
- *
- * @private
- * @param str value potential URI component to check.
- * @returns {boolean} True if `value` can be decoded
- * with the decodeURIComponent function.
- */
-function tryDecodeURIComponent(value) {
- try {
- return decodeURIComponent(value);
- } catch (e) {
- // Ignore any invalid uri component
- }
-}
-
-
-/**
- * Parses an escaped url query string into key-value pairs.
- * @returns {Object.}
- */
-function parseKeyValue(/**string*/keyValue) {
- var obj = {};
- forEach((keyValue || "").split('&'), function(keyValue) {
- var splitPoint, key, val;
- if (keyValue) {
- key = keyValue = keyValue.replace(/\+/g,'%20');
- splitPoint = keyValue.indexOf('=');
- if (splitPoint !== -1) {
- key = keyValue.substring(0, splitPoint);
- val = keyValue.substring(splitPoint + 1);
- }
- key = tryDecodeURIComponent(key);
- if (isDefined(key)) {
- val = isDefined(val) ? tryDecodeURIComponent(val) : true;
- if (!hasOwnProperty.call(obj, key)) {
- obj[key] = val;
- } else if (isArray(obj[key])) {
- obj[key].push(val);
- } else {
- obj[key] = [obj[key],val];
- }
- }
- }
- });
- return obj;
-}
-
-function toKeyValue(obj) {
- var parts = [];
- forEach(obj, function(value, key) {
- if (isArray(value)) {
- forEach(value, function(arrayValue) {
- parts.push(encodeUriQuery(key, true) +
- (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
- });
- } else {
- parts.push(encodeUriQuery(key, true) +
- (value === true ? '' : '=' + encodeUriQuery(value, true)));
- }
- });
- return parts.length ? parts.join('&') : '';
-}
-
-
-/**
- * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
- * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
- * segments:
- * segment = *pchar
- * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
- * pct-encoded = "%" HEXDIG HEXDIG
- * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
- * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
- * / "*" / "+" / "," / ";" / "="
- */
-function encodeUriSegment(val) {
- return encodeUriQuery(val, true).
- replace(/%26/gi, '&').
- replace(/%3D/gi, '=').
- replace(/%2B/gi, '+');
-}
-
-
-/**
- * This method is intended for encoding *key* or *value* parts of query component. We need a custom
- * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
- * encoded per http://tools.ietf.org/html/rfc3986:
- * query = *( pchar / "/" / "?" )
- * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
- * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
- * pct-encoded = "%" HEXDIG HEXDIG
- * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
- * / "*" / "+" / "," / ";" / "="
- */
-function encodeUriQuery(val, pctEncodeSpaces) {
- return encodeURIComponent(val).
- replace(/%40/gi, '@').
- replace(/%3A/gi, ':').
- replace(/%24/g, '$').
- replace(/%2C/gi, ',').
- replace(/%3B/gi, ';').
- replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
-}
-
-var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
-
-function getNgAttribute(element, ngAttr) {
- var attr, i, ii = ngAttrPrefixes.length;
- for (i = 0; i < ii; ++i) {
- attr = ngAttrPrefixes[i] + ngAttr;
- if (isString(attr = element.getAttribute(attr))) {
- return attr;
- }
- }
- return null;
-}
-
-/**
- * @ngdoc directive
- * @name ngApp
- * @module ng
- *
- * @element ANY
- * @param {angular.Module} ngApp an optional application
- * {@link angular.module module} name to load.
- * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
- * created in "strict-di" mode. This means that the application will fail to invoke functions which
- * do not use explicit function annotation (and are thus unsuitable for minification), as described
- * in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
- * tracking down the root of these bugs.
- *
- * @description
- *
- * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
- * designates the **root element** of the application and is typically placed near the root element
- * of the page - e.g. on the `` or `` tags.
- *
- * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
- * found in the document will be used to define the root element to auto-bootstrap as an
- * application. To run multiple applications in an HTML document you must manually bootstrap them using
- * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
- *
- * You can specify an **AngularJS module** to be used as the root module for the application. This
- * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
- * should contain the application code needed or have dependencies on other modules that will
- * contain the code. See {@link angular.module} for more information.
- *
- * In the example below if the `ngApp` directive were not placed on the `html` element then the
- * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
- * would not be resolved to `3`.
- *
- * `ngApp` is the easiest, and most common way to bootstrap an application.
- *
-
-
-
- I can add: {{a}} + {{b}} = {{ a+b }}
-
-
-
- angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
- $scope.a = 1;
- $scope.b = 2;
- });
-
-
- *
- * Using `ngStrictDi`, you would see something like this:
- *
-
-
-
-
- I can add: {{a}} + {{b}} = {{ a+b }}
-
-
This renders because the controller does not fail to
- instantiate, by using explicit annotation style (see
- script.js for details)
-
-
-
-
- Name:
- Hello, {{name}}!
-
-
This renders because the controller does not fail to
- instantiate, by using explicit annotation style
- (see script.js for details)
-
-
-
-
- I can add: {{a}} + {{b}} = {{ a+b }}
-
-
The controller could not be instantiated, due to relying
- on automatic function annotations (which are disabled in
- strict mode). As such, the content of this section is not
- interpolated, and there should be an error in your web console.
-
-
-
-
-
- angular.module('ngAppStrictDemo', [])
- // BadController will fail to instantiate, due to relying on automatic function annotation,
- // rather than an explicit annotation
- .controller('BadController', function($scope) {
- $scope.a = 1;
- $scope.b = 2;
- })
- // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
- // due to using explicit annotations using the array style and $inject property, respectively.
- .controller('GoodController1', ['$scope', function($scope) {
- $scope.a = 1;
- $scope.b = 2;
- }])
- .controller('GoodController2', GoodController2);
- function GoodController2($scope) {
- $scope.name = "World";
- }
- GoodController2.$inject = ['$scope'];
-
-
- div[ng-controller] {
- margin-bottom: 1em;
- -webkit-border-radius: 4px;
- border-radius: 4px;
- border: 1px solid;
- padding: .5em;
- }
- div[ng-controller^=Good] {
- border-color: #d6e9c6;
- background-color: #dff0d8;
- color: #3c763d;
- }
- div[ng-controller^=Bad] {
- border-color: #ebccd1;
- background-color: #f2dede;
- color: #a94442;
- margin-bottom: 0;
- }
-
-
- */
-function angularInit(element, bootstrap) {
- var appElement,
- module,
- config = {};
-
- // The element `element` has priority over any other element
- forEach(ngAttrPrefixes, function(prefix) {
- var name = prefix + 'app';
-
- if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
- appElement = element;
- module = element.getAttribute(name);
- }
- });
- forEach(ngAttrPrefixes, function(prefix) {
- var name = prefix + 'app';
- var candidate;
-
- if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
- appElement = candidate;
- module = candidate.getAttribute(name);
- }
- });
- if (appElement) {
- config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
- bootstrap(appElement, module ? [module] : [], config);
- }
-}
-
-/**
- * @ngdoc function
- * @name angular.bootstrap
- * @module ng
- * @description
- * Use this function to manually start up angular application.
- *
- * See: {@link guide/bootstrap Bootstrap}
- *
- * Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
- * They must use {@link ng.directive:ngApp ngApp}.
- *
- * Angular will detect if it has been loaded into the browser more than once and only allow the
- * first loaded script to be bootstrapped and will report a warning to the browser console for
- * each of the subsequent scripts. This prevents strange results in applications, where otherwise
- * multiple instances of Angular try to work on the DOM.
- *
- * ```html
- *
- *
- *
- *
- * {{greeting}}
- *
- *
- *
- *
- *
- *
- * ```
- *
- * @param {DOMElement} element DOM element which is the root of angular application.
- * @param {Array=} modules an array of modules to load into the application.
- * Each item in the array should be the name of a predefined module or a (DI annotated)
- * function that will be invoked by the injector as a `config` block.
- * See: {@link angular.module modules}
- * @param {Object=} config an object for defining configuration options for the application. The
- * following keys are supported:
- *
- * * `strictDi` - disable automatic function annotation for the application. This is meant to
- * assist in finding bugs which break minified code. Defaults to `false`.
- *
- * @returns {auto.$injector} Returns the newly created injector for this app.
- */
-function bootstrap(element, modules, config) {
- if (!isObject(config)) config = {};
- var defaultConfig = {
- strictDi: false
- };
- config = extend(defaultConfig, config);
- var doBootstrap = function() {
- element = jqLite(element);
-
- if (element.injector()) {
- var tag = (element[0] === document) ? 'document' : startingTag(element);
- //Encode angle brackets to prevent input from being sanitized to empty string #8683
- throw ngMinErr(
- 'btstrpd',
- "App Already Bootstrapped with this Element '{0}'",
- tag.replace(/,'<').replace(/>/,'>'));
- }
-
- modules = modules || [];
- modules.unshift(['$provide', function($provide) {
- $provide.value('$rootElement', element);
- }]);
-
- if (config.debugInfoEnabled) {
- // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
- modules.push(['$compileProvider', function($compileProvider) {
- $compileProvider.debugInfoEnabled(true);
- }]);
- }
-
- modules.unshift('ng');
- var injector = createInjector(modules, config.strictDi);
- injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
- function bootstrapApply(scope, element, compile, injector) {
- scope.$apply(function() {
- element.data('$injector', injector);
- compile(element)(scope);
- });
- }]
- );
- return injector;
- };
-
- var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
- var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
-
- if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
- config.debugInfoEnabled = true;
- window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
- }
-
- if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
- return doBootstrap();
- }
-
- window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
- angular.resumeBootstrap = function(extraModules) {
- forEach(extraModules, function(module) {
- modules.push(module);
- });
- return doBootstrap();
- };
-
- if (isFunction(angular.resumeDeferredBootstrap)) {
- angular.resumeDeferredBootstrap();
- }
-}
-
-/**
- * @ngdoc function
- * @name angular.reloadWithDebugInfo
- * @module ng
- * @description
- * Use this function to reload the current application with debug information turned on.
- * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
- *
- * See {@link ng.$compileProvider#debugInfoEnabled} for more.
- */
-function reloadWithDebugInfo() {
- window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
- window.location.reload();
-}
-
-/**
- * @name angular.getTestability
- * @module ng
- * @description
- * Get the testability service for the instance of Angular on the given
- * element.
- * @param {DOMElement} element DOM element which is the root of angular application.
- */
-function getTestability(rootElement) {
- var injector = angular.element(rootElement).injector();
- if (!injector) {
- throw ngMinErr('test',
- 'no injector found for element argument to getTestability');
- }
- return injector.get('$$testability');
-}
-
-var SNAKE_CASE_REGEXP = /[A-Z]/g;
-function snake_case(name, separator) {
- separator = separator || '_';
- return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
- return (pos ? separator : '') + letter.toLowerCase();
- });
-}
-
-var bindJQueryFired = false;
-function bindJQuery() {
- var originalCleanData;
-
- if (bindJQueryFired) {
- return;
- }
-
- // bind to jQuery if present;
- var jqName = jq();
- jQuery = isUndefined(jqName) ? window.jQuery : // use jQuery (if present)
- !jqName ? undefined : // use jqLite
- window[jqName]; // use jQuery specified by `ngJq`
-
- // Use jQuery if it exists with proper functionality, otherwise default to us.
- // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
- // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
- // versions. It will not work for sure with jQuery <1.7, though.
- if (jQuery && jQuery.fn.on) {
- jqLite = jQuery;
- extend(jQuery.fn, {
- scope: JQLitePrototype.scope,
- isolateScope: JQLitePrototype.isolateScope,
- controller: JQLitePrototype.controller,
- injector: JQLitePrototype.injector,
- inheritedData: JQLitePrototype.inheritedData
- });
-
- // All nodes removed from the DOM via various jQuery APIs like .remove()
- // are passed through jQuery.cleanData. Monkey-patch this method to fire
- // the $destroy event on all removed nodes.
- originalCleanData = jQuery.cleanData;
- jQuery.cleanData = function(elems) {
- var events;
- for (var i = 0, elem; (elem = elems[i]) != null; i++) {
- events = jQuery._data(elem, "events");
- if (events && events.$destroy) {
- jQuery(elem).triggerHandler('$destroy');
- }
- }
- originalCleanData(elems);
- };
- } else {
- jqLite = JQLite;
- }
-
- angular.element = jqLite;
-
- // Prevent double-proxying.
- bindJQueryFired = true;
-}
-
-/**
- * throw error if the argument is falsy.
- */
-function assertArg(arg, name, reason) {
- if (!arg) {
- throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
- }
- return arg;
-}
-
-function assertArgFn(arg, name, acceptArrayAnnotation) {
- if (acceptArrayAnnotation && isArray(arg)) {
- arg = arg[arg.length - 1];
- }
-
- assertArg(isFunction(arg), name, 'not a function, got ' +
- (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
- return arg;
-}
-
-/**
- * throw error if the name given is hasOwnProperty
- * @param {String} name the name to test
- * @param {String} context the context in which the name is used, such as module or directive
- */
-function assertNotHasOwnProperty(name, context) {
- if (name === 'hasOwnProperty') {
- throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
- }
-}
-
-/**
- * Return the value accessible from the object by path. Any undefined traversals are ignored
- * @param {Object} obj starting object
- * @param {String} path path to traverse
- * @param {boolean} [bindFnToScope=true]
- * @returns {Object} value as accessible by path
- */
-//TODO(misko): this function needs to be removed
-function getter(obj, path, bindFnToScope) {
- if (!path) return obj;
- var keys = path.split('.');
- var key;
- var lastInstance = obj;
- var len = keys.length;
-
- for (var i = 0; i < len; i++) {
- key = keys[i];
- if (obj) {
- obj = (lastInstance = obj)[key];
- }
- }
- if (!bindFnToScope && isFunction(obj)) {
- return bind(lastInstance, obj);
- }
- return obj;
-}
-
-/**
- * Return the DOM siblings between the first and last node in the given array.
- * @param {Array} array like object
- * @returns {Array} the inputted object or a jqLite collection containing the nodes
- */
-function getBlockNodes(nodes) {
- // TODO(perf): update `nodes` instead of creating a new object?
- var node = nodes[0];
- var endNode = nodes[nodes.length - 1];
- var blockNodes;
-
- for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
- if (blockNodes || nodes[i] !== node) {
- if (!blockNodes) {
- blockNodes = jqLite(slice.call(nodes, 0, i));
- }
- blockNodes.push(node);
- }
- }
-
- return blockNodes || nodes;
-}
-
-
-/**
- * Creates a new object without a prototype. This object is useful for lookup without having to
- * guard against prototypically inherited properties via hasOwnProperty.
- *
- * Related micro-benchmarks:
- * - http://jsperf.com/object-create2
- * - http://jsperf.com/proto-map-lookup/2
- * - http://jsperf.com/for-in-vs-object-keys2
- *
- * @returns {Object}
- */
-function createMap() {
- return Object.create(null);
-}
-
-var NODE_TYPE_ELEMENT = 1;
-var NODE_TYPE_ATTRIBUTE = 2;
-var NODE_TYPE_TEXT = 3;
-var NODE_TYPE_COMMENT = 8;
-var NODE_TYPE_DOCUMENT = 9;
-var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
-
-/**
- * @ngdoc type
- * @name angular.Module
- * @module ng
- * @description
- *
- * Interface for configuring angular {@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.} */
- var modules = {};
-
- /**
- * @ngdoc function
- * @name angular.module
- * @module ng
- * @description
- *
- * The `angular.module` is a global place for creating, registering and retrieving Angular
- * modules.
- * All modules (angular 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.=} 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 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.>} */
- var invokeQueue = [];
-
- /** @type {!Array.} */
- var configBlocks = [];
-
- /** @type {!Array.} */
- var runBlocks = [];
-
- var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
-
- /** @type {angular.Module} */
- var moduleInstance = {
- // Private state
- _invokeQueue: invokeQueue,
- _configBlocks: configBlocks,
- _runBlocks: runBlocks,
-
- /**
- * @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} The name of the service to decorate.
- * @param {Function} 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'),
-
- /**
- * @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 angular expression identifier
- * @param {Function} filterFactory Factory function for creating new instance of filter.
- * @description
- * See {@link ng.$filterProvider#register $filterProvider.register()}.
- *
- *
- * **Note:** Filter names must be valid angular {@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`).
- *
- */
- 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} name Name of the component in camel-case (i.e. myComp which will match as my-comp)
- * @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 register work which needs to be performed on module loading.
- * 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) {
- return function(recipeName, factoryFunction) {
- if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
- invokeQueue.push([provider, method, arguments]);
- return moduleInstance;
- };
- }
- });
- };
- });
-
-}
-
-/* global: toDebugString: true */
-
-function serializeObject(obj) {
- var seen = [];
-
- 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) {
- if (typeof obj === 'function') {
- return obj.toString().replace(/ \{[\s\S]*$/, '');
- } else if (isUndefined(obj)) {
- return 'undefined';
- } else if (typeof obj !== 'string') {
- return serializeObject(obj);
- }
- return obj;
-}
-
-/* global angularModule: true,
- version: true,
-
- $CompileProvider,
-
- htmlAnchorDirective,
- inputDirective,
- inputDirective,
- formDirective,
- scriptDirective,
- selectDirective,
- styleDirective,
- optionDirective,
- ngBindDirective,
- ngBindHtmlDirective,
- ngBindTemplateDirective,
- ngClassDirective,
- ngClassEvenDirective,
- ngClassOddDirective,
- ngCloakDirective,
- ngControllerDirective,
- ngFormDirective,
- ngHideDirective,
- ngIfDirective,
- ngIncludeDirective,
- ngIncludeFillContentDirective,
- ngInitDirective,
- ngNonBindableDirective,
- ngPluralizeDirective,
- ngRepeatDirective,
- ngShowDirective,
- ngStyleDirective,
- ngSwitchDirective,
- ngSwitchWhenDirective,
- ngSwitchDefaultDirective,
- ngOptionsDirective,
- ngTranscludeDirective,
- ngModelDirective,
- ngListDirective,
- ngChangeDirective,
- patternDirective,
- patternDirective,
- requiredDirective,
- requiredDirective,
- minlengthDirective,
- minlengthDirective,
- maxlengthDirective,
- maxlengthDirective,
- ngValueDirective,
- ngModelOptionsDirective,
- ngAttributeAliasDirectives,
- ngEventDirectives,
-
- $AnchorScrollProvider,
- $AnimateProvider,
- $CoreAnimateCssProvider,
- $$CoreAnimateJsProvider,
- $$CoreAnimateQueueProvider,
- $$AnimateRunnerFactoryProvider,
- $$AnimateAsyncRunFactoryProvider,
- $BrowserProvider,
- $CacheFactoryProvider,
- $ControllerProvider,
- $DateProvider,
- $DocumentProvider,
- $ExceptionHandlerProvider,
- $FilterProvider,
- $$ForceReflowProvider,
- $InterpolateProvider,
- $IntervalProvider,
- $$HashMapProvider,
- $HttpProvider,
- $HttpParamSerializerProvider,
- $HttpParamSerializerJQLikeProvider,
- $HttpBackendProvider,
- $xhrFactoryProvider,
- $LocationProvider,
- $LogProvider,
- $ParseProvider,
- $RootScopeProvider,
- $QProvider,
- $$QProvider,
- $$SanitizeUriProvider,
- $SceProvider,
- $SceDelegateProvider,
- $SnifferProvider,
- $TemplateCacheProvider,
- $TemplateRequestProvider,
- $$TestabilityProvider,
- $TimeoutProvider,
- $$RAFProvider,
- $WindowProvider,
- $$jqLiteProvider,
- $$CookieReaderProvider
-*/
-
-
-/**
- * @ngdoc object
- * @name angular.version
- * @module ng
- * @description
- * An object that contains information about the current AngularJS version.
- *
- * This object has the following properties:
- *
- * - `full` – `{string}` – Full version string, such as "0.9.18".
- * - `major` – `{number}` – Major version number, such as "0".
- * - `minor` – `{number}` – Minor version number, such as "9".
- * - `dot` – `{number}` – Dot version number, such as "18".
- * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
- */
-var version = {
- full: '1.5.0', // all of these placeholder strings will be replaced by grunt's
- major: 1, // package task
- minor: 5,
- dot: 0,
- codeName: 'ennoblement-facilitation'
-};
-
-
-function publishExternalAPI(angular) {
- extend(angular, {
- 'bootstrap': bootstrap,
- 'copy': copy,
- 'extend': extend,
- 'merge': merge,
- 'equals': equals,
- 'element': jqLite,
- 'forEach': forEach,
- 'injector': createInjector,
- 'noop': noop,
- 'bind': bind,
- 'toJson': toJson,
- 'fromJson': fromJson,
- 'identity': identity,
- 'isUndefined': isUndefined,
- 'isDefined': isDefined,
- 'isString': isString,
- 'isFunction': isFunction,
- 'isObject': isObject,
- 'isNumber': isNumber,
- 'isElement': isElement,
- 'isArray': isArray,
- 'version': version,
- 'isDate': isDate,
- 'lowercase': lowercase,
- 'uppercase': uppercase,
- 'callbacks': {counter: 0},
- 'getTestability': getTestability,
- '$$minErr': minErr,
- '$$csp': csp,
- 'reloadWithDebugInfo': reloadWithDebugInfo
- });
-
- angularModule = setupModuleLoader(window);
-
- angularModule('ng', ['ngLocale'], ['$provide',
- function ngModule($provide) {
- // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
- $provide.provider({
- $$sanitizeUri: $$SanitizeUriProvider
- });
- $provide.provider('$compile', $CompileProvider).
- directive({
- a: htmlAnchorDirective,
- input: inputDirective,
- textarea: inputDirective,
- form: formDirective,
- script: scriptDirective,
- select: selectDirective,
- style: styleDirective,
- option: optionDirective,
- ngBind: ngBindDirective,
- ngBindHtml: ngBindHtmlDirective,
- ngBindTemplate: ngBindTemplateDirective,
- ngClass: ngClassDirective,
- ngClassEven: ngClassEvenDirective,
- ngClassOdd: ngClassOddDirective,
- ngCloak: ngCloakDirective,
- ngController: ngControllerDirective,
- ngForm: ngFormDirective,
- ngHide: ngHideDirective,
- ngIf: ngIfDirective,
- ngInclude: ngIncludeDirective,
- ngInit: ngInitDirective,
- ngNonBindable: ngNonBindableDirective,
- ngPluralize: ngPluralizeDirective,
- ngRepeat: ngRepeatDirective,
- ngShow: ngShowDirective,
- ngStyle: ngStyleDirective,
- ngSwitch: ngSwitchDirective,
- ngSwitchWhen: ngSwitchWhenDirective,
- ngSwitchDefault: ngSwitchDefaultDirective,
- ngOptions: ngOptionsDirective,
- ngTransclude: ngTranscludeDirective,
- ngModel: ngModelDirective,
- ngList: ngListDirective,
- ngChange: ngChangeDirective,
- pattern: patternDirective,
- ngPattern: patternDirective,
- required: requiredDirective,
- ngRequired: requiredDirective,
- minlength: minlengthDirective,
- ngMinlength: minlengthDirective,
- maxlength: maxlengthDirective,
- ngMaxlength: maxlengthDirective,
- ngValue: ngValueDirective,
- ngModelOptions: ngModelOptionsDirective
- }).
- directive({
- ngInclude: ngIncludeFillContentDirective
- }).
- directive(ngAttributeAliasDirectives).
- directive(ngEventDirectives);
- $provide.provider({
- $anchorScroll: $AnchorScrollProvider,
- $animate: $AnimateProvider,
- $animateCss: $CoreAnimateCssProvider,
- $$animateJs: $$CoreAnimateJsProvider,
- $$animateQueue: $$CoreAnimateQueueProvider,
- $$AnimateRunner: $$AnimateRunnerFactoryProvider,
- $$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,
- $browser: $BrowserProvider,
- $cacheFactory: $CacheFactoryProvider,
- $controller: $ControllerProvider,
- $document: $DocumentProvider,
- $exceptionHandler: $ExceptionHandlerProvider,
- $filter: $FilterProvider,
- $$forceReflow: $$ForceReflowProvider,
- $interpolate: $InterpolateProvider,
- $interval: $IntervalProvider,
- $http: $HttpProvider,
- $httpParamSerializer: $HttpParamSerializerProvider,
- $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
- $httpBackend: $HttpBackendProvider,
- $xhrFactory: $xhrFactoryProvider,
- $location: $LocationProvider,
- $log: $LogProvider,
- $parse: $ParseProvider,
- $rootScope: $RootScopeProvider,
- $q: $QProvider,
- $$q: $$QProvider,
- $sce: $SceProvider,
- $sceDelegate: $SceDelegateProvider,
- $sniffer: $SnifferProvider,
- $templateCache: $TemplateCacheProvider,
- $templateRequest: $TemplateRequestProvider,
- $$testability: $$TestabilityProvider,
- $timeout: $TimeoutProvider,
- $window: $WindowProvider,
- $$rAF: $$RAFProvider,
- $$jqLite: $$jqLiteProvider,
- $$HashMap: $$HashMapProvider,
- $$cookieReader: $$CookieReaderProvider
- });
- }
- ]);
-}
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * 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? *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-/* global JQLitePrototype: true,
- addEventListenerFn: true,
- removeEventListenerFn: true,
- BOOLEAN_ATTR: true,
- ALIASED_ATTR: true,
-*/
-
-//////////////////////////////////
-//JQLite
-//////////////////////////////////
-
-/**
- * @ngdoc function
- * @name angular.element
- * @module ng
- * @kind function
- *
- * @description
- * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
- *
- * If jQuery is available, `angular.element` is an alias for the
- * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
- * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or **jqLite**.
- *
- * jqLite is a tiny, API-compatible subset of jQuery that allows
- * Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most
- * commonly needed functionality with the goal of having a very small footprint.
- *
- * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the
- * {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a
- * specific version of jQuery if multiple versions exist on the page.
- *
- *
**Note:** All element references in Angular are always wrapped with jQuery or
- * jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.
- *
- *
**Note:** Keep in mind that this function will not find elements
- * by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)`
- * or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.
- *
- * ## Angular's jqLite
- * jqLite provides only the following jQuery methods:
- *
- * - [`addClass()`](http://api.jquery.com/addClass/)
- * - [`after()`](http://api.jquery.com/after/)
- * - [`append()`](http://api.jquery.com/append/)
- * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
- * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
- * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
- * - [`clone()`](http://api.jquery.com/clone/)
- * - [`contents()`](http://api.jquery.com/contents/)
- * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`.
- * As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing.
- * - [`data()`](http://api.jquery.com/data/)
- * - [`detach()`](http://api.jquery.com/detach/)
- * - [`empty()`](http://api.jquery.com/empty/)
- * - [`eq()`](http://api.jquery.com/eq/)
- * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
- * - [`hasClass()`](http://api.jquery.com/hasClass/)
- * - [`html()`](http://api.jquery.com/html/)
- * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
- * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
- * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
- * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
- * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
- * - [`prepend()`](http://api.jquery.com/prepend/)
- * - [`prop()`](http://api.jquery.com/prop/)
- * - [`ready()`](http://api.jquery.com/ready/)
- * - [`remove()`](http://api.jquery.com/remove/)
- * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
- * - [`removeClass()`](http://api.jquery.com/removeClass/)
- * - [`removeData()`](http://api.jquery.com/removeData/)
- * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
- * - [`text()`](http://api.jquery.com/text/)
- * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
- * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
- * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter
- * - [`val()`](http://api.jquery.com/val/)
- * - [`wrap()`](http://api.jquery.com/wrap/)
- *
- * ## jQuery/jqLite Extras
- * Angular also provides the following additional methods and events to both jQuery and jqLite:
- *
- * ### Events
- * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
- * on all DOM nodes being removed. This can be used to clean up any 3rd party bindings to the DOM
- * element before it is removed.
- *
- * ### Methods
- * - `controller(name)` - retrieves the controller of the current element or its parent. By default
- * retrieves controller associated with the `ngController` directive. If `name` is provided as
- * camelCase directive name, then the controller for this directive will be retrieved (e.g.
- * `'ngModel'`).
- * - `injector()` - retrieves the injector of the current element or its parent.
- * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
- * element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
- * be enabled.
- * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
- * current element. This getter should be used only on elements that contain a directive which starts a new isolate
- * scope. Calling `scope()` on this element always returns the original non-isolate scope.
- * Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
- * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
- * parent element is reached.
- *
- * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
- * @returns {Object} jQuery object.
- */
-
-JQLite.expando = 'ng339';
-
-var jqCache = JQLite.cache = {},
- jqId = 1,
- addEventListenerFn = function(element, type, fn) {
- element.addEventListener(type, fn, false);
- },
- removeEventListenerFn = function(element, type, fn) {
- element.removeEventListener(type, fn, false);
- };
-
-/*
- * !!! This is an undocumented "private" function !!!
- */
-JQLite._data = function(node) {
- //jQuery always returns an object on cache miss
- return this.cache[node[this.expando]] || {};
-};
-
-function jqNextId() { return ++jqId; }
-
-
-var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
-var MOZ_HACK_REGEXP = /^moz([A-Z])/;
-var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
-var jqLiteMinErr = minErr('jqLite');
-
-/**
- * Converts snake_case to camelCase.
- * Also there is special case for Moz prefix starting with upper case letter.
- * @param name Name to normalize
- */
-function camelCase(name) {
- return name.
- replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
- return offset ? letter.toUpperCase() : letter;
- }).
- replace(MOZ_HACK_REGEXP, 'Moz$1');
-}
-
-var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
-var HTML_REGEXP = /<|?\w+;/;
-var TAG_NAME_REGEXP = /<([\w:-]+)/;
-var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
-
-var wrapMap = {
- 'option': [1, ''],
-
- 'thead': [1, '
', '
'],
- 'col': [2, '
', '
'],
- 'tr': [2, '
', '
'],
- 'td': [3, '
', '
'],
- '_default': [0, "", ""]
-};
-
-wrapMap.optgroup = wrapMap.option;
-wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
-wrapMap.th = wrapMap.td;
-
-
-function jqLiteIsTextNode(html) {
- return !HTML_REGEXP.test(html);
-}
-
-function jqLiteAcceptsData(node) {
- // The window object can accept data but has no nodeType
- // Otherwise we are only interested in elements (1) and documents (9)
- var nodeType = node.nodeType;
- return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
-}
-
-function jqLiteHasData(node) {
- for (var key in jqCache[node.ng339]) {
- return true;
- }
- return false;
-}
-
-function jqLiteCleanData(nodes) {
- for (var i = 0, ii = nodes.length; i < ii; i++) {
- jqLiteRemoveData(nodes[i]);
- }
-}
-
-function jqLiteBuildFragment(html, context) {
- var tmp, tag, wrap,
- fragment = context.createDocumentFragment(),
- nodes = [], i;
-
- if (jqLiteIsTextNode(html)) {
- // Convert non-html into a text node
- nodes.push(context.createTextNode(html));
- } else {
- // Convert html into DOM nodes
- tmp = tmp || fragment.appendChild(context.createElement("div"));
- tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
- wrap = wrapMap[tag] || wrapMap._default;
- tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1>$2>") + wrap[2];
-
- // Descend through wrappers to the right content
- i = wrap[0];
- while (i--) {
- tmp = tmp.lastChild;
- }
-
- nodes = concat(nodes, tmp.childNodes);
-
- tmp = fragment.firstChild;
- tmp.textContent = "";
- }
-
- // Remove wrapper from fragment
- fragment.textContent = "";
- fragment.innerHTML = ""; // Clear inner HTML
- forEach(nodes, function(node) {
- fragment.appendChild(node);
- });
-
- return fragment;
-}
-
-function jqLiteParseHTML(html, context) {
- context = context || document;
- var parsed;
-
- if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
- return [context.createElement(parsed[1])];
- }
-
- if ((parsed = jqLiteBuildFragment(html, context))) {
- return parsed.childNodes;
- }
-
- return [];
-}
-
-function jqLiteWrapNode(node, wrapper) {
- var parent = node.parentNode;
-
- if (parent) {
- parent.replaceChild(wrapper, node);
- }
-
- wrapper.appendChild(node);
-}
-
-
-// IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
-var jqLiteContains = Node.prototype.contains || function(arg) {
- // jshint bitwise: false
- return !!(this.compareDocumentPosition(arg) & 16);
- // jshint bitwise: true
-};
-
-/////////////////////////////////////////////
-function JQLite(element) {
- if (element instanceof JQLite) {
- return element;
- }
-
- var argIsString;
-
- if (isString(element)) {
- element = trim(element);
- argIsString = true;
- }
- if (!(this instanceof JQLite)) {
- if (argIsString && element.charAt(0) != '<') {
- throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
- }
- return new JQLite(element);
- }
-
- if (argIsString) {
- jqLiteAddNodes(this, jqLiteParseHTML(element));
- } else {
- jqLiteAddNodes(this, element);
- }
-}
-
-function jqLiteClone(element) {
- return element.cloneNode(true);
-}
-
-function jqLiteDealoc(element, onlyDescendants) {
- if (!onlyDescendants) jqLiteRemoveData(element);
-
- if (element.querySelectorAll) {
- var descendants = element.querySelectorAll('*');
- for (var i = 0, l = descendants.length; i < l; i++) {
- jqLiteRemoveData(descendants[i]);
- }
- }
-}
-
-function jqLiteOff(element, type, fn, unsupported) {
- if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
-
- var expandoStore = jqLiteExpandoStore(element);
- var events = expandoStore && expandoStore.events;
- var handle = expandoStore && expandoStore.handle;
-
- if (!handle) return; //no listeners registered
-
- if (!type) {
- for (type in events) {
- if (type !== '$destroy') {
- removeEventListenerFn(element, type, handle);
- }
- delete events[type];
- }
- } else {
-
- var removeHandler = function(type) {
- var listenerFns = events[type];
- if (isDefined(fn)) {
- arrayRemove(listenerFns || [], fn);
- }
- if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
- removeEventListenerFn(element, type, handle);
- delete events[type];
- }
- };
-
- forEach(type.split(' '), function(type) {
- removeHandler(type);
- if (MOUSE_EVENT_MAP[type]) {
- removeHandler(MOUSE_EVENT_MAP[type]);
- }
- });
- }
-}
-
-function jqLiteRemoveData(element, name) {
- var expandoId = element.ng339;
- var expandoStore = expandoId && jqCache[expandoId];
-
- if (expandoStore) {
- if (name) {
- delete expandoStore.data[name];
- return;
- }
-
- if (expandoStore.handle) {
- if (expandoStore.events.$destroy) {
- expandoStore.handle({}, '$destroy');
- }
- jqLiteOff(element);
- }
- delete jqCache[expandoId];
- element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
- }
-}
-
-
-function jqLiteExpandoStore(element, createIfNecessary) {
- var expandoId = element.ng339,
- expandoStore = expandoId && jqCache[expandoId];
-
- if (createIfNecessary && !expandoStore) {
- element.ng339 = expandoId = jqNextId();
- expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
- }
-
- return expandoStore;
-}
-
-
-function jqLiteData(element, key, value) {
- if (jqLiteAcceptsData(element)) {
-
- var isSimpleSetter = isDefined(value);
- var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
- var massGetter = !key;
- var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
- var data = expandoStore && expandoStore.data;
-
- if (isSimpleSetter) { // data('key', value)
- data[key] = value;
- } else {
- if (massGetter) { // data()
- return data;
- } else {
- if (isSimpleGetter) { // data('key')
- // don't force creation of expandoStore if it doesn't exist yet
- return data && data[key];
- } else { // mass-setter: data({key1: val1, key2: val2})
- extend(data, key);
- }
- }
- }
- }
-}
-
-function jqLiteHasClass(element, selector) {
- if (!element.getAttribute) return false;
- return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
- indexOf(" " + selector + " ") > -1);
-}
-
-function jqLiteRemoveClass(element, cssClasses) {
- if (cssClasses && element.setAttribute) {
- forEach(cssClasses.split(' '), function(cssClass) {
- element.setAttribute('class', trim(
- (" " + (element.getAttribute('class') || '') + " ")
- .replace(/[\n\t]/g, " ")
- .replace(" " + trim(cssClass) + " ", " "))
- );
- });
- }
-}
-
-function jqLiteAddClass(element, cssClasses) {
- if (cssClasses && element.setAttribute) {
- var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
- .replace(/[\n\t]/g, " ");
-
- forEach(cssClasses.split(' '), function(cssClass) {
- cssClass = trim(cssClass);
- if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
- existingClasses += cssClass + ' ';
- }
- });
-
- element.setAttribute('class', trim(existingClasses));
- }
-}
-
-
-function jqLiteAddNodes(root, elements) {
- // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
-
- if (elements) {
-
- // if a Node (the most common case)
- if (elements.nodeType) {
- root[root.length++] = elements;
- } else {
- var length = elements.length;
-
- // if an Array or NodeList and not a Window
- if (typeof length === 'number' && elements.window !== elements) {
- if (length) {
- for (var i = 0; i < length; i++) {
- root[root.length++] = elements[i];
- }
- }
- } else {
- root[root.length++] = elements;
- }
- }
- }
-}
-
-
-function jqLiteController(element, name) {
- return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
-}
-
-function jqLiteInheritedData(element, name, value) {
- // if element is the document object work with the html element instead
- // this makes $(document).scope() possible
- if (element.nodeType == NODE_TYPE_DOCUMENT) {
- element = element.documentElement;
- }
- var names = isArray(name) ? name : [name];
-
- while (element) {
- for (var i = 0, ii = names.length; i < ii; i++) {
- if (isDefined(value = jqLite.data(element, names[i]))) return value;
- }
-
- // If dealing with a document fragment node with a host element, and no parent, use the host
- // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
- // to lookup parent controllers.
- element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
- }
-}
-
-function jqLiteEmpty(element) {
- jqLiteDealoc(element, true);
- while (element.firstChild) {
- element.removeChild(element.firstChild);
- }
-}
-
-function jqLiteRemove(element, keepData) {
- if (!keepData) jqLiteDealoc(element);
- var parent = element.parentNode;
- if (parent) parent.removeChild(element);
-}
-
-
-function jqLiteDocumentLoaded(action, win) {
- win = win || window;
- if (win.document.readyState === 'complete') {
- // Force the action to be run async for consistent behavior
- // from the action's point of view
- // i.e. it will definitely not be in a $apply
- win.setTimeout(action);
- } else {
- // No need to unbind this handler as load is only ever called once
- jqLite(win).on('load', action);
- }
-}
-
-//////////////////////////////////////////
-// Functions which are declared directly.
-//////////////////////////////////////////
-var JQLitePrototype = JQLite.prototype = {
- ready: function(fn) {
- var fired = false;
-
- function trigger() {
- if (fired) return;
- fired = true;
- fn();
- }
-
- // check if document is already loaded
- if (document.readyState === 'complete') {
- setTimeout(trigger);
- } else {
- this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
- // we can not use jqLite since we are not done loading and jQuery could be loaded later.
- // jshint -W064
- JQLite(window).on('load', trigger); // fallback to window.onload for others
- // jshint +W064
- }
- },
- toString: function() {
- var value = [];
- forEach(this, function(e) { value.push('' + e);});
- return '[' + value.join(', ') + ']';
- },
-
- eq: function(index) {
- return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
- },
-
- length: 0,
- push: push,
- sort: [].sort,
- splice: [].splice
-};
-
-//////////////////////////////////////////
-// Functions iterating getter/setters.
-// these functions return self on setter and
-// value on get.
-//////////////////////////////////////////
-var BOOLEAN_ATTR = {};
-forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
- BOOLEAN_ATTR[lowercase(value)] = value;
-});
-var BOOLEAN_ELEMENTS = {};
-forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
- BOOLEAN_ELEMENTS[value] = true;
-});
-var ALIASED_ATTR = {
- 'ngMinlength': 'minlength',
- 'ngMaxlength': 'maxlength',
- 'ngMin': 'min',
- 'ngMax': 'max',
- 'ngPattern': 'pattern'
-};
-
-function getBooleanAttrName(element, name) {
- // check dom last since we will most likely fail on name
- var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
-
- // booleanAttr is here twice to minimize DOM access
- return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
-}
-
-function getAliasedAttrName(name) {
- return ALIASED_ATTR[name];
-}
-
-forEach({
- data: jqLiteData,
- removeData: jqLiteRemoveData,
- hasData: jqLiteHasData,
- cleanData: jqLiteCleanData
-}, function(fn, name) {
- JQLite[name] = fn;
-});
-
-forEach({
- data: jqLiteData,
- inheritedData: jqLiteInheritedData,
-
- scope: function(element) {
- // Can't use jqLiteData here directly so we stay compatible with jQuery!
- return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
- },
-
- isolateScope: function(element) {
- // Can't use jqLiteData here directly so we stay compatible with jQuery!
- return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
- },
-
- controller: jqLiteController,
-
- injector: function(element) {
- return jqLiteInheritedData(element, '$injector');
- },
-
- removeAttr: function(element, name) {
- element.removeAttribute(name);
- },
-
- hasClass: jqLiteHasClass,
-
- css: function(element, name, value) {
- name = camelCase(name);
-
- if (isDefined(value)) {
- element.style[name] = value;
- } else {
- return element.style[name];
- }
- },
-
- attr: function(element, name, value) {
- var nodeType = element.nodeType;
- if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
- return;
- }
- var lowercasedName = lowercase(name);
- if (BOOLEAN_ATTR[lowercasedName]) {
- if (isDefined(value)) {
- if (!!value) {
- element[name] = true;
- element.setAttribute(name, lowercasedName);
- } else {
- element[name] = false;
- element.removeAttribute(lowercasedName);
- }
- } else {
- return (element[name] ||
- (element.attributes.getNamedItem(name) || noop).specified)
- ? lowercasedName
- : undefined;
- }
- } else if (isDefined(value)) {
- element.setAttribute(name, value);
- } else if (element.getAttribute) {
- // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
- // some elements (e.g. Document) don't have get attribute, so return undefined
- var ret = element.getAttribute(name, 2);
- // normalize non-existing attributes to undefined (as jQuery)
- return ret === null ? undefined : ret;
- }
- },
-
- prop: function(element, name, value) {
- if (isDefined(value)) {
- element[name] = value;
- } else {
- return element[name];
- }
- },
-
- text: (function() {
- getText.$dv = '';
- return getText;
-
- function getText(element, value) {
- if (isUndefined(value)) {
- var nodeType = element.nodeType;
- return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
- }
- element.textContent = value;
- }
- })(),
-
- val: function(element, value) {
- if (isUndefined(value)) {
- if (element.multiple && nodeName_(element) === 'select') {
- var result = [];
- forEach(element.options, function(option) {
- if (option.selected) {
- result.push(option.value || option.text);
- }
- });
- return result.length === 0 ? null : result;
- }
- return element.value;
- }
- element.value = value;
- },
-
- html: function(element, value) {
- if (isUndefined(value)) {
- return element.innerHTML;
- }
- jqLiteDealoc(element, true);
- element.innerHTML = value;
- },
-
- empty: jqLiteEmpty
-}, function(fn, name) {
- /**
- * Properties: writes return selection, reads return first value
- */
- JQLite.prototype[name] = function(arg1, arg2) {
- var i, key;
- var nodeCount = this.length;
-
- // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
- // in a way that survives minification.
- // jqLiteEmpty takes no arguments but is a setter.
- if (fn !== jqLiteEmpty &&
- (isUndefined((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
- if (isObject(arg1)) {
-
- // we are a write, but the object properties are the key/values
- for (i = 0; i < nodeCount; i++) {
- if (fn === jqLiteData) {
- // data() takes the whole object in jQuery
- fn(this[i], arg1);
- } else {
- for (key in arg1) {
- fn(this[i], key, arg1[key]);
- }
- }
- }
- // return self for chaining
- return this;
- } else {
- // we are a read, so read the first child.
- // TODO: do we still need this?
- var value = fn.$dv;
- // Only if we have $dv do we iterate over all, otherwise it is just the first element.
- var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
- for (var j = 0; j < jj; j++) {
- var nodeValue = fn(this[j], arg1, arg2);
- value = value ? value + nodeValue : nodeValue;
- }
- return value;
- }
- } else {
- // we are a write, so apply to all children
- for (i = 0; i < nodeCount; i++) {
- fn(this[i], arg1, arg2);
- }
- // return self for chaining
- return this;
- }
- };
-});
-
-function createEventHandler(element, events) {
- var eventHandler = function(event, type) {
- // jQuery specific api
- event.isDefaultPrevented = function() {
- return event.defaultPrevented;
- };
-
- var eventFns = events[type || event.type];
- var eventFnsLength = eventFns ? eventFns.length : 0;
-
- if (!eventFnsLength) return;
-
- if (isUndefined(event.immediatePropagationStopped)) {
- var originalStopImmediatePropagation = event.stopImmediatePropagation;
- event.stopImmediatePropagation = function() {
- event.immediatePropagationStopped = true;
-
- if (event.stopPropagation) {
- event.stopPropagation();
- }
-
- if (originalStopImmediatePropagation) {
- originalStopImmediatePropagation.call(event);
- }
- };
- }
-
- event.isImmediatePropagationStopped = function() {
- return event.immediatePropagationStopped === true;
- };
-
- // Some events have special handlers that wrap the real handler
- var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;
-
- // Copy event handlers in case event handlers array is modified during execution.
- if ((eventFnsLength > 1)) {
- eventFns = shallowCopy(eventFns);
- }
-
- for (var i = 0; i < eventFnsLength; i++) {
- if (!event.isImmediatePropagationStopped()) {
- handlerWrapper(element, event, eventFns[i]);
- }
- }
- };
-
- // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
- // events on `element`
- eventHandler.elem = element;
- return eventHandler;
-}
-
-function defaultHandlerWrapper(element, event, handler) {
- handler.call(element, event);
-}
-
-function specialMouseHandlerWrapper(target, event, handler) {
- // Refer to jQuery's implementation of mouseenter & mouseleave
- // Read about mouseenter and mouseleave:
- // http://www.quirksmode.org/js/events_mouse.html#link8
- var related = event.relatedTarget;
- // For mousenter/leave call the handler if related is outside the target.
- // NB: No relatedTarget if the mouse left/entered the browser window
- if (!related || (related !== target && !jqLiteContains.call(target, related))) {
- handler.call(target, event);
- }
-}
-
-//////////////////////////////////////////
-// Functions iterating traversal.
-// These functions chain results into a single
-// selector.
-//////////////////////////////////////////
-forEach({
- removeData: jqLiteRemoveData,
-
- on: function jqLiteOn(element, type, fn, unsupported) {
- if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
-
- // Do not add event handlers to non-elements because they will not be cleaned up.
- if (!jqLiteAcceptsData(element)) {
- return;
- }
-
- var expandoStore = jqLiteExpandoStore(element, true);
- var events = expandoStore.events;
- var handle = expandoStore.handle;
-
- if (!handle) {
- handle = expandoStore.handle = createEventHandler(element, events);
- }
-
- // http://jsperf.com/string-indexof-vs-split
- var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
- var i = types.length;
-
- var addHandler = function(type, specialHandlerWrapper, noEventListener) {
- var eventFns = events[type];
-
- if (!eventFns) {
- eventFns = events[type] = [];
- eventFns.specialHandlerWrapper = specialHandlerWrapper;
- if (type !== '$destroy' && !noEventListener) {
- addEventListenerFn(element, type, handle);
- }
- }
-
- eventFns.push(fn);
- };
-
- while (i--) {
- type = types[i];
- if (MOUSE_EVENT_MAP[type]) {
- addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
- addHandler(type, undefined, true);
- } else {
- addHandler(type);
- }
- }
- },
-
- off: jqLiteOff,
-
- one: function(element, type, fn) {
- element = jqLite(element);
-
- //add the listener twice so that when it is called
- //you can remove the original function and still be
- //able to call element.off(ev, fn) normally
- element.on(type, function onFn() {
- element.off(type, fn);
- element.off(type, onFn);
- });
- element.on(type, fn);
- },
-
- replaceWith: function(element, replaceNode) {
- var index, parent = element.parentNode;
- jqLiteDealoc(element);
- forEach(new JQLite(replaceNode), function(node) {
- if (index) {
- parent.insertBefore(node, index.nextSibling);
- } else {
- parent.replaceChild(node, element);
- }
- index = node;
- });
- },
-
- children: function(element) {
- var children = [];
- forEach(element.childNodes, function(element) {
- if (element.nodeType === NODE_TYPE_ELEMENT) {
- children.push(element);
- }
- });
- return children;
- },
-
- contents: function(element) {
- return element.contentDocument || element.childNodes || [];
- },
-
- append: function(element, node) {
- var nodeType = element.nodeType;
- if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
-
- node = new JQLite(node);
-
- for (var i = 0, ii = node.length; i < ii; i++) {
- var child = node[i];
- element.appendChild(child);
- }
- },
-
- prepend: function(element, node) {
- if (element.nodeType === NODE_TYPE_ELEMENT) {
- var index = element.firstChild;
- forEach(new JQLite(node), function(child) {
- element.insertBefore(child, index);
- });
- }
- },
-
- wrap: function(element, wrapNode) {
- jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]);
- },
-
- remove: jqLiteRemove,
-
- detach: function(element) {
- jqLiteRemove(element, true);
- },
-
- after: function(element, newElement) {
- var index = element, parent = element.parentNode;
- newElement = new JQLite(newElement);
-
- for (var i = 0, ii = newElement.length; i < ii; i++) {
- var node = newElement[i];
- parent.insertBefore(node, index.nextSibling);
- index = node;
- }
- },
-
- addClass: jqLiteAddClass,
- removeClass: jqLiteRemoveClass,
-
- toggleClass: function(element, selector, condition) {
- if (selector) {
- forEach(selector.split(' '), function(className) {
- var classCondition = condition;
- if (isUndefined(classCondition)) {
- classCondition = !jqLiteHasClass(element, className);
- }
- (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
- });
- }
- },
-
- parent: function(element) {
- var parent = element.parentNode;
- return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
- },
-
- next: function(element) {
- return element.nextElementSibling;
- },
-
- find: function(element, selector) {
- if (element.getElementsByTagName) {
- return element.getElementsByTagName(selector);
- } else {
- return [];
- }
- },
-
- clone: jqLiteClone,
-
- triggerHandler: function(element, event, extraParameters) {
-
- var dummyEvent, eventFnsCopy, handlerArgs;
- var eventName = event.type || event;
- var expandoStore = jqLiteExpandoStore(element);
- var events = expandoStore && expandoStore.events;
- var eventFns = events && events[eventName];
-
- if (eventFns) {
- // Create a dummy event to pass to the handlers
- dummyEvent = {
- preventDefault: function() { this.defaultPrevented = true; },
- isDefaultPrevented: function() { return this.defaultPrevented === true; },
- stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
- isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
- stopPropagation: noop,
- type: eventName,
- target: element
- };
-
- // If a custom event was provided then extend our dummy event with it
- if (event.type) {
- dummyEvent = extend(dummyEvent, event);
- }
-
- // Copy event handlers in case event handlers array is modified during execution.
- eventFnsCopy = shallowCopy(eventFns);
- handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
-
- forEach(eventFnsCopy, function(fn) {
- if (!dummyEvent.isImmediatePropagationStopped()) {
- fn.apply(element, handlerArgs);
- }
- });
- }
- }
-}, function(fn, name) {
- /**
- * chaining functions
- */
- JQLite.prototype[name] = function(arg1, arg2, arg3) {
- var value;
-
- for (var i = 0, ii = this.length; i < ii; i++) {
- if (isUndefined(value)) {
- value = fn(this[i], arg1, arg2, arg3);
- if (isDefined(value)) {
- // any function which returns a value needs to be wrapped
- value = jqLite(value);
- }
- } else {
- jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
- }
- }
- return isDefined(value) ? value : this;
- };
-
- // bind legacy bind/unbind to on/off
- JQLite.prototype.bind = JQLite.prototype.on;
- JQLite.prototype.unbind = JQLite.prototype.off;
-});
-
-
-// Provider for private $$jqLite service
-function $$jqLiteProvider() {
- this.$get = function $$jqLite() {
- return extend(JQLite, {
- hasClass: function(node, classes) {
- if (node.attr) node = node[0];
- return jqLiteHasClass(node, classes);
- },
- addClass: function(node, classes) {
- if (node.attr) node = node[0];
- return jqLiteAddClass(node, classes);
- },
- removeClass: function(node, classes) {
- if (node.attr) node = node[0];
- return jqLiteRemoveClass(node, classes);
- }
- });
- };
-}
-
-/**
- * Computes a hash of an 'obj'.
- * Hash of a:
- * string is string
- * number is number as string
- * object is either result of calling $$hashKey function on the object or uniquely generated id,
- * that is also assigned to the $$hashKey property of the object.
- *
- * @param obj
- * @returns {string} hash string such that the same input will have the same hash string.
- * The resulting string key is in 'type:hashKey' format.
- */
-function hashKey(obj, nextUidFn) {
- var key = obj && obj.$$hashKey;
-
- if (key) {
- if (typeof key === 'function') {
- key = obj.$$hashKey();
- }
- return key;
- }
-
- var objType = typeof obj;
- if (objType == 'function' || (objType == 'object' && obj !== null)) {
- key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
- } else {
- key = objType + ':' + obj;
- }
-
- return key;
-}
-
-/**
- * HashMap which can use objects as keys
- */
-function HashMap(array, isolatedUid) {
- if (isolatedUid) {
- var uid = 0;
- this.nextUid = function() {
- return ++uid;
- };
- }
- forEach(array, this.put, this);
-}
-HashMap.prototype = {
- /**
- * Store key value pair
- * @param key key to store can be any type
- * @param value value to store can be any type
- */
- put: function(key, value) {
- this[hashKey(key, this.nextUid)] = value;
- },
-
- /**
- * @param key
- * @returns {Object} the value for the key
- */
- get: function(key) {
- return this[hashKey(key, this.nextUid)];
- },
-
- /**
- * Remove the key/value pair
- * @param key
- */
- remove: function(key) {
- var value = this[key = hashKey(key, this.nextUid)];
- delete this[key];
- return value;
- }
-};
-
-var $$HashMapProvider = [function() {
- this.$get = [function() {
- return HashMap;
- }];
-}];
-
-/**
- * @ngdoc function
- * @module ng
- * @name angular.injector
- * @kind function
- *
- * @description
- * Creates an injector object that can be used for retrieving services as well as for
- * dependency injection (see {@link guide/di dependency injection}).
- *
- * @param {Array.} modules A list of module functions or their aliases. See
- * {@link angular.module}. The `ng` module must be explicitly added.
- * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
- * disallows argument name annotation inference.
- * @returns {injector} Injector object. See {@link auto.$injector $injector}.
- *
- * @example
- * Typical usage
- * ```js
- * // create an injector
- * var $injector = angular.injector(['ng']);
- *
- * // use the injector to kick off your application
- * // use the type inference to auto inject arguments, or use implicit injection
- * $injector.invoke(function($rootScope, $compile, $document) {
- * $compile($document)($rootScope);
- * $rootScope.$digest();
- * });
- * ```
- *
- * Sometimes you want to get access to the injector of a currently running Angular app
- * from outside Angular. Perhaps, you want to inject and compile some markup after the
- * application has been bootstrapped. You can do this using the extra `injector()` added
- * to JQuery/jqLite elements. See {@link angular.element}.
- *
- * *This is fairly rare but could be the case if a third party library is injecting the
- * markup.*
- *
- * In the following example a new block of HTML containing a `ng-controller`
- * directive is added to the end of the document body by JQuery. We then compile and link
- * it into the current AngularJS scope.
- *
- * ```js
- * var $div = $('
{{content.label}}
');
- * $(document.body).append($div);
- *
- * angular.element(document).injector().invoke(function($compile) {
- * var scope = angular.element($div).scope();
- * $compile($div)(scope);
- * });
- * ```
- */
-
-
-/**
- * @ngdoc module
- * @name auto
- * @description
- *
- * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
- */
-
-var ARROW_ARG = /^([^\(]+?)=>/;
-var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
-var FN_ARG_SPLIT = /,/;
-var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
-var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
-var $injectorMinErr = minErr('$injector');
-
-function extractArgs(fn) {
- var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
- args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
- return args;
-}
-
-function anonFn(fn) {
- // For anonymous functions, showing at the very least the function signature can help in
- // debugging.
- var args = extractArgs(fn);
- if (args) {
- return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
- }
- return 'fn';
-}
-
-function annotate(fn, strictDi, name) {
- var $inject,
- argDecl,
- last;
-
- if (typeof fn === 'function') {
- if (!($inject = fn.$inject)) {
- $inject = [];
- if (fn.length) {
- if (strictDi) {
- if (!isString(name) || !name) {
- name = fn.name || anonFn(fn);
- }
- throw $injectorMinErr('strictdi',
- '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
- }
- argDecl = extractArgs(fn);
- forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
- arg.replace(FN_ARG, function(all, underscore, name) {
- $inject.push(name);
- });
- });
- }
- fn.$inject = $inject;
- }
- } else if (isArray(fn)) {
- last = fn.length - 1;
- assertArgFn(fn[last], 'fn');
- $inject = fn.slice(0, last);
- } else {
- assertArgFn(fn, 'fn', true);
- }
- return $inject;
-}
-
-///////////////////////////////////////
-
-/**
- * @ngdoc service
- * @name $injector
- *
- * @description
- *
- * `$injector` is used to retrieve object instances as defined by
- * {@link auto.$provide provider}, instantiate types, invoke methods,
- * and load modules.
- *
- * The following always holds true:
- *
- * ```js
- * var $injector = angular.injector();
- * expect($injector.get('$injector')).toBe($injector);
- * expect($injector.invoke(function($injector) {
- * return $injector;
- * })).toBe($injector);
- * ```
- *
- * # Injection Function Annotation
- *
- * JavaScript does not have annotations, and annotations are needed for dependency injection. The
- * following are all valid ways of annotating function with injection arguments and are equivalent.
- *
- * ```js
- * // inferred (only works if code not minified/obfuscated)
- * $injector.invoke(function(serviceA){});
- *
- * // annotated
- * function explicit(serviceA) {};
- * explicit.$inject = ['serviceA'];
- * $injector.invoke(explicit);
- *
- * // inline
- * $injector.invoke(['serviceA', function(serviceA){}]);
- * ```
- *
- * ## Inference
- *
- * In JavaScript calling `toString()` on a function returns the function definition. The definition
- * can then be parsed and the function arguments can be extracted. This method of discovering
- * annotations is disallowed when the injector is in strict mode.
- * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
- * argument names.
- *
- * ## `$inject` Annotation
- * By adding an `$inject` property onto a function the injection parameters can be specified.
- *
- * ## Inline
- * As an array of injection names, where the last item in the array is the function to call.
- */
-
-/**
- * @ngdoc method
- * @name $injector#get
- *
- * @description
- * Return an instance of the service.
- *
- * @param {string} name The name of the instance to retrieve.
- * @param {string=} caller An optional string to provide the origin of the function call for error messages.
- * @return {*} The instance.
- */
-
-/**
- * @ngdoc method
- * @name $injector#invoke
- *
- * @description
- * Invoke the method and supply the method arguments from the `$injector`.
- *
- * @param {Function|Array.} fn The injectable function to invoke. Function parameters are
- * injected according to the {@link guide/di $inject Annotation} rules.
- * @param {Object=} self The `this` for the invoked method.
- * @param {Object=} locals Optional object. If preset then any argument names are read from this
- * object first, before the `$injector` is consulted.
- * @returns {*} the value returned by the invoked `fn` function.
- */
-
-/**
- * @ngdoc method
- * @name $injector#has
- *
- * @description
- * Allows the user to query if the particular service exists.
- *
- * @param {string} name Name of the service to query.
- * @returns {boolean} `true` if injector has given service.
- */
-
-/**
- * @ngdoc method
- * @name $injector#instantiate
- * @description
- * Create a new instance of JS type. The method takes a constructor function, invokes the new
- * operator, and supplies all of the arguments to the constructor function as specified by the
- * constructor annotation.
- *
- * @param {Function} Type Annotated constructor function.
- * @param {Object=} locals Optional object. If preset then any argument names are read from this
- * object first, before the `$injector` is consulted.
- * @returns {Object} new instance of `Type`.
- */
-
-/**
- * @ngdoc method
- * @name $injector#annotate
- *
- * @description
- * Returns an array of service names which the function is requesting for injection. This API is
- * used by the injector to determine which services need to be injected into the function when the
- * function is invoked. There are three ways in which the function can be annotated with the needed
- * dependencies.
- *
- * # Argument names
- *
- * The simplest form is to extract the dependencies from the arguments of the function. This is done
- * by converting the function into a string using `toString()` method and extracting the argument
- * names.
- * ```js
- * // Given
- * function MyController($scope, $route) {
- * // ...
- * }
- *
- * // Then
- * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
- * ```
- *
- * You can disallow this method by using strict injection mode.
- *
- * This method does not work with code minification / obfuscation. For this reason the following
- * annotation strategies are supported.
- *
- * # The `$inject` property
- *
- * If a function has an `$inject` property and its value is an array of strings, then the strings
- * represent names of services to be injected into the function.
- * ```js
- * // Given
- * var MyController = function(obfuscatedScope, obfuscatedRoute) {
- * // ...
- * }
- * // Define function dependencies
- * MyController['$inject'] = ['$scope', '$route'];
- *
- * // Then
- * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
- * ```
- *
- * # The array notation
- *
- * It is often desirable to inline Injected functions and that's when setting the `$inject` property
- * is very inconvenient. In these situations using the array notation to specify the dependencies in
- * a way that survives minification is a better choice:
- *
- * ```js
- * // We wish to write this (not minification / obfuscation safe)
- * injector.invoke(function($compile, $rootScope) {
- * // ...
- * });
- *
- * // We are forced to write break inlining
- * var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
- * // ...
- * };
- * tmpFn.$inject = ['$compile', '$rootScope'];
- * injector.invoke(tmpFn);
- *
- * // To better support inline function the inline annotation is supported
- * injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
- * // ...
- * }]);
- *
- * // Therefore
- * expect(injector.annotate(
- * ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
- * ).toEqual(['$compile', '$rootScope']);
- * ```
- *
- * @param {Function|Array.} fn Function for which dependent service names need to
- * be retrieved as described above.
- *
- * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
- *
- * @returns {Array.} The names of the services which the function requires.
- */
-
-
-
-
-/**
- * @ngdoc service
- * @name $provide
- *
- * @description
- *
- * The {@link auto.$provide $provide} service has a number of methods for registering components
- * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
- * {@link angular.Module}.
- *
- * An Angular **service** is a singleton object created by a **service factory**. These **service
- * factories** are functions which, in turn, are created by a **service provider**.
- * The **service providers** are constructor functions. When instantiated they must contain a
- * property called `$get`, which holds the **service factory** function.
- *
- * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
- * correct **service provider**, instantiating it and then calling its `$get` **service factory**
- * function to get the instance of the **service**.
- *
- * Often services have no configuration options and there is no need to add methods to the service
- * provider. The provider will be no more than a constructor function with a `$get` property. For
- * these cases the {@link auto.$provide $provide} service has additional helper methods to register
- * services without specifying a provider.
- *
- * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
- * {@link auto.$injector $injector}
- * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
- * providers and services.
- * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
- * services, not providers.
- * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
- * that will be wrapped in a **service provider** object, whose `$get` property will contain the
- * given factory function.
- * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
- * that will be wrapped in a **service provider** object, whose `$get` property will instantiate
- * a new object using the given constructor function.
- *
- * See the individual methods for more information and examples.
- */
-
-/**
- * @ngdoc method
- * @name $provide#provider
- * @description
- *
- * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
- * are constructor functions, whose instances are responsible for "providing" a factory for a
- * service.
- *
- * Service provider names start with the name of the service they provide followed by `Provider`.
- * For example, the {@link ng.$log $log} service has a provider called
- * {@link ng.$logProvider $logProvider}.
- *
- * Service provider objects can have additional methods which allow configuration of the provider
- * and its service. Importantly, you can configure what kind of service is created by the `$get`
- * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
- * method {@link ng.$logProvider#debugEnabled debugEnabled}
- * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
- * console or not.
- *
- * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
- 'Provider'` key.
- * @param {(Object|function())} provider If the provider is:
- *
- * - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
- * {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
- * - `Constructor`: a new instance of the provider will be created using
- * {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
- *
- * @returns {Object} registered provider instance
-
- * @example
- *
- * The following example shows how to create a simple event tracking service and register it using
- * {@link auto.$provide#provider $provide.provider()}.
- *
- * ```js
- * // Define the eventTracker provider
- * function EventTrackerProvider() {
- * var trackingUrl = '/track';
- *
- * // A provider method for configuring where the tracked events should been saved
- * this.setTrackingUrl = function(url) {
- * trackingUrl = url;
- * };
- *
- * // The service factory function
- * this.$get = ['$http', function($http) {
- * var trackedEvents = {};
- * return {
- * // Call this to track an event
- * event: function(event) {
- * var count = trackedEvents[event] || 0;
- * count += 1;
- * trackedEvents[event] = count;
- * return count;
- * },
- * // Call this to save the tracked events to the trackingUrl
- * save: function() {
- * $http.post(trackingUrl, trackedEvents);
- * }
- * };
- * }];
- * }
- *
- * describe('eventTracker', function() {
- * var postSpy;
- *
- * beforeEach(module(function($provide) {
- * // Register the eventTracker provider
- * $provide.provider('eventTracker', EventTrackerProvider);
- * }));
- *
- * beforeEach(module(function(eventTrackerProvider) {
- * // Configure eventTracker provider
- * eventTrackerProvider.setTrackingUrl('/custom-track');
- * }));
- *
- * it('tracks events', inject(function(eventTracker) {
- * expect(eventTracker.event('login')).toEqual(1);
- * expect(eventTracker.event('login')).toEqual(2);
- * }));
- *
- * it('saves to the tracking url', inject(function(eventTracker, $http) {
- * postSpy = spyOn($http, 'post');
- * eventTracker.event('login');
- * eventTracker.save();
- * expect(postSpy).toHaveBeenCalled();
- * expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
- * expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
- * expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
- * }));
- * });
- * ```
- */
-
-/**
- * @ngdoc method
- * @name $provide#factory
- * @description
- *
- * Register a **service factory**, which will be called to return the service instance.
- * This is short for registering a service where its provider consists of only a `$get` property,
- * which is the given service factory function.
- * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
- * configure your service in a provider.
- *
- * @param {string} name The name of the instance.
- * @param {Function|Array.} $getFn The injectable $getFn for the instance creation.
- * Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
- * @returns {Object} registered provider instance
- *
- * @example
- * Here is an example of registering a service
- * ```js
- * $provide.factory('ping', ['$http', function($http) {
- * return function ping() {
- * return $http.send('/ping');
- * };
- * }]);
- * ```
- * You would then inject and use this service like this:
- * ```js
- * someModule.controller('Ctrl', ['ping', function(ping) {
- * ping();
- * }]);
- * ```
- */
-
-
-/**
- * @ngdoc method
- * @name $provide#service
- * @description
- *
- * Register a **service constructor**, which will be invoked with `new` to create the service
- * instance.
- * This is short for registering a service where its provider's `$get` property is a factory
- * function that returns an instance instantiated by the injector from the service constructor
- * function.
- *
- * Internally it looks a bit like this:
- *
- * ```
- * {
- * $get: function() {
- * return $injector.instantiate(constructor);
- * }
- * }
- * ```
- *
- *
- * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
- * as a type/class.
- *
- * @param {string} name The name of the instance.
- * @param {Function|Array.} constructor An injectable class (constructor function)
- * that will be instantiated.
- * @returns {Object} registered provider instance
- *
- * @example
- * Here is an example of registering a service using
- * {@link auto.$provide#service $provide.service(class)}.
- * ```js
- * var Ping = function($http) {
- * this.$http = $http;
- * };
- *
- * Ping.$inject = ['$http'];
- *
- * Ping.prototype.send = function() {
- * return this.$http.get('/ping');
- * };
- * $provide.service('ping', Ping);
- * ```
- * You would then inject and use this service like this:
- * ```js
- * someModule.controller('Ctrl', ['ping', function(ping) {
- * ping.send();
- * }]);
- * ```
- */
-
-
-/**
- * @ngdoc method
- * @name $provide#value
- * @description
- *
- * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
- * number, an array, an object or a function. This is short for registering a service where its
- * provider's `$get` property is a factory function that takes no arguments and returns the **value
- * service**.
- *
- * Value services are similar to constant services, except that they cannot be injected into a
- * module configuration function (see {@link angular.Module#config}) but they can be overridden by
- * an Angular
- * {@link auto.$provide#decorator decorator}.
- *
- * @param {string} name The name of the instance.
- * @param {*} value The value.
- * @returns {Object} registered provider instance
- *
- * @example
- * Here are some examples of creating value services.
- * ```js
- * $provide.value('ADMIN_USER', 'admin');
- *
- * $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
- *
- * $provide.value('halfOf', function(value) {
- * return value / 2;
- * });
- * ```
- */
-
-
-/**
- * @ngdoc method
- * @name $provide#constant
- * @description
- *
- * Register a **constant service**, such as a string, a number, an array, an object or a function,
- * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
- * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
- * be overridden by an Angular {@link auto.$provide#decorator decorator}.
- *
- * @param {string} name The name of the constant.
- * @param {*} value The constant value.
- * @returns {Object} registered instance
- *
- * @example
- * Here a some examples of creating constants:
- * ```js
- * $provide.constant('SHARD_HEIGHT', 306);
- *
- * $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
- *
- * $provide.constant('double', function(value) {
- * return value * 2;
- * });
- * ```
- */
-
-
-/**
- * @ngdoc method
- * @name $provide#decorator
- * @description
- *
- * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
- * intercepts the creation of a service, allowing it to override or modify the behavior of the
- * service. The object returned by the decorator may be the original service, or a new service
- * object which replaces or wraps and delegates to the original service.
- *
- * @param {string} name The name of the service to decorate.
- * @param {Function|Array.} decorator This function will be invoked when the service needs to be
- * instantiated and should return the decorated service instance. The function is called using
- * the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
- * Local injection arguments:
- *
- * * `$delegate` - The original service instance, which can be monkey patched, configured,
- * decorated or delegated to.
- *
- * @example
- * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
- * calls to {@link ng.$log#error $log.warn()}.
- * ```js
- * $provide.decorator('$log', ['$delegate', function($delegate) {
- * $delegate.warn = $delegate.error;
- * return $delegate;
- * }]);
- * ```
- */
-
-
-function createInjector(modulesToLoad, strictDi) {
- strictDi = (strictDi === true);
- var INSTANTIATING = {},
- providerSuffix = 'Provider',
- path = [],
- loadedModules = new HashMap([], true),
- providerCache = {
- $provide: {
- provider: supportObject(provider),
- factory: supportObject(factory),
- service: supportObject(service),
- value: supportObject(value),
- constant: supportObject(constant),
- decorator: decorator
- }
- },
- providerInjector = (providerCache.$injector =
- createInternalInjector(providerCache, function(serviceName, caller) {
- if (angular.isString(caller)) {
- path.push(caller);
- }
- throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
- })),
- instanceCache = {},
- protoInstanceInjector =
- createInternalInjector(instanceCache, function(serviceName, caller) {
- var provider = providerInjector.get(serviceName + providerSuffix, caller);
- return instanceInjector.invoke(
- provider.$get, provider, undefined, serviceName);
- }),
- instanceInjector = protoInstanceInjector;
-
- providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
- var runBlocks = loadModules(modulesToLoad);
- instanceInjector = protoInstanceInjector.get('$injector');
- instanceInjector.strictDi = strictDi;
- forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); });
-
- return instanceInjector;
-
- ////////////////////////////////////
- // $provider
- ////////////////////////////////////
-
- function supportObject(delegate) {
- return function(key, value) {
- if (isObject(key)) {
- forEach(key, reverseParams(delegate));
- } else {
- return delegate(key, value);
- }
- };
- }
-
- function provider(name, provider_) {
- assertNotHasOwnProperty(name, 'service');
- if (isFunction(provider_) || isArray(provider_)) {
- provider_ = providerInjector.instantiate(provider_);
- }
- if (!provider_.$get) {
- throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
- }
- return providerCache[name + providerSuffix] = provider_;
- }
-
- function enforceReturnValue(name, factory) {
- return function enforcedReturnValue() {
- var result = instanceInjector.invoke(factory, this);
- if (isUndefined(result)) {
- throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
- }
- return result;
- };
- }
-
- function factory(name, factoryFn, enforce) {
- return provider(name, {
- $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
- });
- }
-
- function service(name, constructor) {
- return factory(name, ['$injector', function($injector) {
- return $injector.instantiate(constructor);
- }]);
- }
-
- function value(name, val) { return factory(name, valueFn(val), false); }
-
- function constant(name, value) {
- assertNotHasOwnProperty(name, 'constant');
- providerCache[name] = value;
- instanceCache[name] = value;
- }
-
- function decorator(serviceName, decorFn) {
- var origProvider = providerInjector.get(serviceName + providerSuffix),
- orig$get = origProvider.$get;
-
- origProvider.$get = function() {
- var origInstance = instanceInjector.invoke(orig$get, origProvider);
- return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
- };
- }
-
- ////////////////////////////////////
- // Module Loading
- ////////////////////////////////////
- function loadModules(modulesToLoad) {
- assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');
- var runBlocks = [], moduleFn;
- forEach(modulesToLoad, function(module) {
- if (loadedModules.get(module)) return;
- loadedModules.put(module, true);
-
- function runInvokeQueue(queue) {
- var i, ii;
- for (i = 0, ii = queue.length; i < ii; i++) {
- var invokeArgs = queue[i],
- provider = providerInjector.get(invokeArgs[0]);
-
- provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
- }
- }
-
- try {
- if (isString(module)) {
- moduleFn = angularModule(module);
- runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
- runInvokeQueue(moduleFn._invokeQueue);
- runInvokeQueue(moduleFn._configBlocks);
- } else if (isFunction(module)) {
- runBlocks.push(providerInjector.invoke(module));
- } else if (isArray(module)) {
- runBlocks.push(providerInjector.invoke(module));
- } else {
- assertArgFn(module, 'module');
- }
- } catch (e) {
- if (isArray(module)) {
- module = module[module.length - 1];
- }
- if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
- // Safari & FF's stack traces don't contain error.message content
- // unlike those of Chrome and IE
- // So if stack doesn't contain message, we create a new string that contains both.
- // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
- /* jshint -W022 */
- e = e.message + '\n' + e.stack;
- }
- throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
- module, e.stack || e.message || e);
- }
- });
- return runBlocks;
- }
-
- ////////////////////////////////////
- // internal Injector
- ////////////////////////////////////
-
- function createInternalInjector(cache, factory) {
-
- function getService(serviceName, caller) {
- if (cache.hasOwnProperty(serviceName)) {
- if (cache[serviceName] === INSTANTIATING) {
- throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
- serviceName + ' <- ' + path.join(' <- '));
- }
- return cache[serviceName];
- } else {
- try {
- path.unshift(serviceName);
- cache[serviceName] = INSTANTIATING;
- return cache[serviceName] = factory(serviceName, caller);
- } catch (err) {
- if (cache[serviceName] === INSTANTIATING) {
- delete cache[serviceName];
- }
- throw err;
- } finally {
- path.shift();
- }
- }
- }
-
-
- function injectionArgs(fn, locals, serviceName) {
- var args = [],
- $inject = createInjector.$$annotate(fn, strictDi, serviceName);
-
- for (var i = 0, length = $inject.length; i < length; i++) {
- var key = $inject[i];
- if (typeof key !== 'string') {
- throw $injectorMinErr('itkn',
- 'Incorrect injection token! Expected service name as string, got {0}', key);
- }
- args.push(locals && locals.hasOwnProperty(key) ? locals[key] :
- getService(key, serviceName));
- }
- return args;
- }
-
- function isClass(func) {
- // IE 9-11 do not support classes and IE9 leaks with the code below.
- if (msie <= 11) {
- return false;
- }
- // Workaround for MS Edge.
- // Check https://connect.microsoft.com/IE/Feedback/Details/2211653
- return typeof func === 'function'
- && /^(?:class\s|constructor\()/.test(Function.prototype.toString.call(func));
- }
-
- function invoke(fn, self, locals, serviceName) {
- if (typeof locals === 'string') {
- serviceName = locals;
- locals = null;
- }
-
- var args = injectionArgs(fn, locals, serviceName);
- if (isArray(fn)) {
- fn = fn[fn.length - 1];
- }
-
- if (!isClass(fn)) {
- // http://jsperf.com/angularjs-invoke-apply-vs-switch
- // #5388
- return fn.apply(self, args);
- } else {
- args.unshift(null);
- return new (Function.prototype.bind.apply(fn, args))();
- }
- }
-
-
- function instantiate(Type, locals, serviceName) {
- // Check if Type is annotated and use just the given function at n-1 as parameter
- // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
- var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
- var args = injectionArgs(Type, locals, serviceName);
- // Empty object at position 0 is ignored for invocation with `new`, but required.
- args.unshift(null);
- return new (Function.prototype.bind.apply(ctor, args))();
- }
-
-
- return {
- invoke: invoke,
- instantiate: instantiate,
- get: getService,
- annotate: createInjector.$$annotate,
- has: function(name) {
- return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
- }
- };
- }
-}
-
-createInjector.$$annotate = annotate;
-
-/**
- * @ngdoc provider
- * @name $anchorScrollProvider
- *
- * @description
- * Use `$anchorScrollProvider` to disable automatic scrolling whenever
- * {@link ng.$location#hash $location.hash()} changes.
- */
-function $AnchorScrollProvider() {
-
- var autoScrollingEnabled = true;
-
- /**
- * @ngdoc method
- * @name $anchorScrollProvider#disableAutoScrolling
- *
- * @description
- * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
- * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.
- * Use this method to disable automatic scrolling.
- *
- * If automatic scrolling is disabled, one must explicitly call
- * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
- * current hash.
- */
- this.disableAutoScrolling = function() {
- autoScrollingEnabled = false;
- };
-
- /**
- * @ngdoc service
- * @name $anchorScroll
- * @kind function
- * @requires $window
- * @requires $location
- * @requires $rootScope
- *
- * @description
- * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
- * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
- * in the
- * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#the-indicated-part-of-the-document).
- *
- * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
- * match any anchor whenever it changes. This can be disabled by calling
- * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
- *
- * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
- * vertical scroll-offset (either fixed or dynamic).
- *
- * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
- * {@link ng.$location#hash $location.hash()} will be used.
- *
- * @property {(number|function|jqLite)} yOffset
- * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
- * positioned elements at the top of the page, such as navbars, headers etc.
- *
- * `yOffset` can be specified in various ways:
- * - **number**: A fixed number of pixels to be used as offset.
- * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
- * a number representing the offset (in pixels).
- * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
- * the top of the page to the element's bottom will be used as offset.
- * **Note**: The element will be taken into account only as long as its `position` is set to
- * `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
- * their height and/or positioning according to the viewport's size.
- *
- *
- *
- * In order for `yOffset` to work properly, scrolling should take place on the document's root and
- * not some child element.
- *
-
-
- angular.module('anchorScrollOffsetExample', [])
- .run(['$anchorScroll', function($anchorScroll) {
- $anchorScroll.yOffset = 50; // always scroll by 50 extra pixels
- }])
- .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
- function ($anchorScroll, $location, $scope) {
- $scope.gotoAnchor = function(x) {
- var newHash = 'anchor' + x;
- if ($location.hash() !== newHash) {
- // set the $location.hash to `newHash` and
- // $anchorScroll will automatically scroll to it
- $location.hash('anchor' + x);
- } else {
- // call $anchorScroll() explicitly,
- // since $location.hash hasn't changed
- $anchorScroll();
- }
- };
- }
- ]);
-
-
- body {
- padding-top: 50px;
- }
-
- .anchor {
- border: 2px dashed DarkOrchid;
- padding: 10px 10px 200px 10px;
- }
-
- .fixed-header {
- background-color: rgba(0, 0, 0, 0.2);
- height: 50px;
- position: fixed;
- top: 0; left: 0; right: 0;
- }
-
- .fixed-header > a {
- display: inline-block;
- margin: 5px 15px;
- }
-
-
- */
- this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
- var document = $window.document;
-
- // Helper function to get first anchor from a NodeList
- // (using `Array#some()` instead of `angular#forEach()` since it's more performant
- // and working in all supported browsers.)
- function getFirstAnchor(list) {
- var result = null;
- Array.prototype.some.call(list, function(element) {
- if (nodeName_(element) === 'a') {
- result = element;
- return true;
- }
- });
- return result;
- }
-
- function getYOffset() {
-
- var offset = scroll.yOffset;
-
- if (isFunction(offset)) {
- offset = offset();
- } else if (isElement(offset)) {
- var elem = offset[0];
- var style = $window.getComputedStyle(elem);
- if (style.position !== 'fixed') {
- offset = 0;
- } else {
- offset = elem.getBoundingClientRect().bottom;
- }
- } else if (!isNumber(offset)) {
- offset = 0;
- }
-
- return offset;
- }
-
- function scrollTo(elem) {
- if (elem) {
- elem.scrollIntoView();
-
- var offset = getYOffset();
-
- if (offset) {
- // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
- // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
- // top of the viewport.
- //
- // IF the number of pixels from the top of `elem` to the end of the page's content is less
- // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
- // way down the page.
- //
- // This is often the case for elements near the bottom of the page.
- //
- // In such cases we do not need to scroll the whole `offset` up, just the difference between
- // the top of the element and the offset, which is enough to align the top of `elem` at the
- // desired position.
- var elemTop = elem.getBoundingClientRect().top;
- $window.scrollBy(0, elemTop - offset);
- }
- } else {
- $window.scrollTo(0, 0);
- }
- }
-
- function scroll(hash) {
- hash = isString(hash) ? hash : $location.hash();
- var elm;
-
- // empty hash, scroll to the top of the page
- if (!hash) scrollTo(null);
-
- // element with given id
- else if ((elm = document.getElementById(hash))) scrollTo(elm);
-
- // first anchor with given name :-D
- else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
-
- // no element and hash == 'top', scroll to the top of the page
- else if (hash === 'top') scrollTo(null);
- }
-
- // does not scroll when user clicks on anchor link that is currently on
- // (no url change, no $location.hash() change), browser native does scroll
- if (autoScrollingEnabled) {
- $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
- function autoScrollWatchAction(newVal, oldVal) {
- // skip the initial scroll if $location.hash is empty
- if (newVal === oldVal && newVal === '') return;
-
- jqLiteDocumentLoaded(function() {
- $rootScope.$evalAsync(scroll);
- });
- });
- }
-
- return scroll;
- }];
-}
-
-var $animateMinErr = minErr('$animate');
-var ELEMENT_NODE = 1;
-var NG_ANIMATE_CLASSNAME = 'ng-animate';
-
-function mergeClasses(a,b) {
- if (!a && !b) return '';
- if (!a) return b;
- if (!b) return a;
- if (isArray(a)) a = a.join(' ');
- if (isArray(b)) b = b.join(' ');
- return a + ' ' + b;
-}
-
-function extractElementNode(element) {
- for (var i = 0; i < element.length; i++) {
- var elm = element[i];
- if (elm.nodeType === ELEMENT_NODE) {
- return elm;
- }
- }
-}
-
-function splitClasses(classes) {
- if (isString(classes)) {
- classes = classes.split(' ');
- }
-
- // Use createMap() to prevent class assumptions involving property names in
- // Object.prototype
- var obj = createMap();
- forEach(classes, function(klass) {
- // sometimes the split leaves empty string values
- // incase extra spaces were applied to the options
- if (klass.length) {
- obj[klass] = true;
- }
- });
- return obj;
-}
-
-// if any other type of options value besides an Object value is
-// passed into the $animate.method() animation then this helper code
-// will be run which will ignore it. While this patch is not the
-// greatest solution to this, a lot of existing plugins depend on
-// $animate to either call the callback (< 1.2) or return a promise
-// that can be changed. This helper function ensures that the options
-// are wiped clean incase a callback function is provided.
-function prepareAnimateOptions(options) {
- return isObject(options)
- ? options
- : {};
-}
-
-var $$CoreAnimateJsProvider = function() {
- this.$get = function() {};
-};
-
-// this is prefixed with Core since it conflicts with
-// the animateQueueProvider defined in ngAnimate/animateQueue.js
-var $$CoreAnimateQueueProvider = function() {
- var postDigestQueue = new HashMap();
- var postDigestElements = [];
-
- this.$get = ['$$AnimateRunner', '$rootScope',
- function($$AnimateRunner, $rootScope) {
- return {
- enabled: noop,
- on: noop,
- off: noop,
- pin: noop,
-
- push: function(element, event, options, domOperation) {
- domOperation && domOperation();
-
- options = options || {};
- options.from && element.css(options.from);
- options.to && element.css(options.to);
-
- if (options.addClass || options.removeClass) {
- addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
- }
-
- var runner = new $$AnimateRunner(); // jshint ignore:line
-
- // since there are no animations to run the runner needs to be
- // notified that the animation call is complete.
- runner.complete();
- return runner;
- }
- };
-
-
- function updateData(data, classes, value) {
- var changed = false;
- if (classes) {
- classes = isString(classes) ? classes.split(' ') :
- isArray(classes) ? classes : [];
- forEach(classes, function(className) {
- if (className) {
- changed = true;
- data[className] = value;
- }
- });
- }
- return changed;
- }
-
- function handleCSSClassChanges() {
- forEach(postDigestElements, function(element) {
- var data = postDigestQueue.get(element);
- if (data) {
- var existing = splitClasses(element.attr('class'));
- var toAdd = '';
- var toRemove = '';
- forEach(data, function(status, className) {
- var hasClass = !!existing[className];
- if (status !== hasClass) {
- if (status) {
- toAdd += (toAdd.length ? ' ' : '') + className;
- } else {
- toRemove += (toRemove.length ? ' ' : '') + className;
- }
- }
- });
-
- forEach(element, function(elm) {
- toAdd && jqLiteAddClass(elm, toAdd);
- toRemove && jqLiteRemoveClass(elm, toRemove);
- });
- postDigestQueue.remove(element);
- }
- });
- postDigestElements.length = 0;
- }
-
-
- function addRemoveClassesPostDigest(element, add, remove) {
- var data = postDigestQueue.get(element) || {};
-
- var classesAdded = updateData(data, add, true);
- var classesRemoved = updateData(data, remove, false);
-
- if (classesAdded || classesRemoved) {
-
- postDigestQueue.put(element, data);
- postDigestElements.push(element);
-
- if (postDigestElements.length === 1) {
- $rootScope.$$postDigest(handleCSSClassChanges);
- }
- }
- }
- }];
-};
-
-/**
- * @ngdoc provider
- * @name $animateProvider
- *
- * @description
- * Default implementation of $animate that doesn't perform any animations, instead just
- * synchronously performs DOM updates and resolves the returned runner promise.
- *
- * In order to enable animations the `ngAnimate` module has to be loaded.
- *
- * To see the functional implementation check out `src/ngAnimate/animate.js`.
- */
-var $AnimateProvider = ['$provide', function($provide) {
- var provider = this;
-
- this.$$registeredAnimations = Object.create(null);
-
- /**
- * @ngdoc method
- * @name $animateProvider#register
- *
- * @description
- * Registers a new injectable animation factory function. The factory function produces the
- * animation object which contains callback functions for each event that is expected to be
- * animated.
- *
- * * `eventFn`: `function(element, ... , doneFunction, options)`
- * The element to animate, the `doneFunction` and the options fed into the animation. Depending
- * on the type of animation additional arguments will be injected into the animation function. The
- * list below explains the function signatures for the different animation methods:
- *
- * - setClass: function(element, addedClasses, removedClasses, doneFunction, options)
- * - addClass: function(element, addedClasses, doneFunction, options)
- * - removeClass: function(element, removedClasses, doneFunction, options)
- * - enter, leave, move: function(element, doneFunction, options)
- * - animate: function(element, fromStyles, toStyles, doneFunction, options)
- *
- * Make sure to trigger the `doneFunction` once the animation is fully complete.
- *
- * ```js
- * return {
- * //enter, leave, move signature
- * eventFn : function(element, done, options) {
- * //code to run the animation
- * //once complete, then run done()
- * return function endFunction(wasCancelled) {
- * //code to cancel the animation
- * }
- * }
- * }
- * ```
- *
- * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).
- * @param {Function} factory The factory function that will be executed to return the animation
- * object.
- */
- this.register = function(name, factory) {
- if (name && name.charAt(0) !== '.') {
- throw $animateMinErr('notcsel', "Expecting class selector starting with '.' got '{0}'.", name);
- }
-
- var key = name + '-animation';
- provider.$$registeredAnimations[name.substr(1)] = key;
- $provide.factory(key, factory);
- };
-
- /**
- * @ngdoc method
- * @name $animateProvider#classNameFilter
- *
- * @description
- * Sets and/or returns the CSS class regular expression that is checked when performing
- * an animation. Upon bootstrap the classNameFilter value is not set at all and will
- * therefore enable $animate to attempt to perform an animation on any element that is triggered.
- * When setting the `classNameFilter` value, animations will only be performed on elements
- * that successfully match the filter expression. This in turn can boost performance
- * for low-powered devices as well as applications containing a lot of structural operations.
- * @param {RegExp=} expression The className expression which will be checked against all animations
- * @return {RegExp} The current CSS className expression value. If null then there is no expression value
- */
- this.classNameFilter = function(expression) {
- if (arguments.length === 1) {
- this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
- if (this.$$classNameFilter) {
- var reservedRegex = new RegExp("(\\s+|\\/)" + NG_ANIMATE_CLASSNAME + "(\\s+|\\/)");
- if (reservedRegex.test(this.$$classNameFilter.toString())) {
- throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
-
- }
- }
- }
- return this.$$classNameFilter;
- };
-
- this.$get = ['$$animateQueue', function($$animateQueue) {
- function domInsert(element, parentElement, afterElement) {
- // if for some reason the previous element was removed
- // from the dom sometime before this code runs then let's
- // just stick to using the parent element as the anchor
- if (afterElement) {
- var afterNode = extractElementNode(afterElement);
- if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {
- afterElement = null;
- }
- }
- afterElement ? afterElement.after(element) : parentElement.prepend(element);
- }
-
- /**
- * @ngdoc service
- * @name $animate
- * @description The $animate service exposes a series of DOM utility methods that provide support
- * for animation hooks. The default behavior is the application of DOM operations, however,
- * when an animation is detected (and animations are enabled), $animate will do the heavy lifting
- * to ensure that animation runs with the triggered DOM operation.
- *
- * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't
- * included and only when it is active then the animation hooks that `$animate` triggers will be
- * functional. Once active then all structural `ng-` directives will trigger animations as they perform
- * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,
- * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.
- *
- * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.
- *
- * To learn more about enabling animation support, click here to visit the
- * {@link ngAnimate ngAnimate module page}.
- */
- return {
- // we don't call it directly since non-existant arguments may
- // be interpreted as null within the sub enabled function
-
- /**
- *
- * @ngdoc method
- * @name $animate#on
- * @kind function
- * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)
- * has fired on the given element or among any of its children. Once the listener is fired, the provided callback
- * is fired with the following params:
- *
- * ```js
- * $animate.on('enter', container,
- * function callback(element, phase) {
- * // cool we detected an enter animation within the container
- * }
- * );
- * ```
- *
- * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)
- * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself
- * as well as among its children
- * @param {Function} callback the callback function that will be fired when the listener is triggered
- *
- * The arguments present in the callback function are:
- * * `element` - The captured DOM element that the animation was fired on.
- * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).
- */
- on: $$animateQueue.on,
-
- /**
- *
- * @ngdoc method
- * @name $animate#off
- * @kind function
- * @description Deregisters an event listener based on the event which has been associated with the provided element. This method
- * can be used in three different ways depending on the arguments:
- *
- * ```js
- * // remove all the animation event listeners listening for `enter`
- * $animate.off('enter');
- *
- * // remove all the animation event listeners listening for `enter` on the given element and its children
- * $animate.off('enter', container);
- *
- * // remove the event listener function provided by `callback` that is set
- * // to listen for `enter` on the given `container` as well as its children
- * $animate.off('enter', container, callback);
- * ```
- *
- * @param {string} event the animation event (e.g. enter, leave, move, addClass, removeClass, etc...)
- * @param {DOMElement=} container the container element the event listener was placed on
- * @param {Function=} callback the callback function that was registered as the listener
- */
- off: $$animateQueue.off,
-
- /**
- * @ngdoc method
- * @name $animate#pin
- * @kind function
- * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists
- * outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the
- * element despite being outside the realm of the application or within another application. Say for example if the application
- * was bootstrapped on an element that is somewhere inside of the `` tag, but we wanted to allow for an element to be situated
- * as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind
- * that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.
- *
- * Note that this feature is only active when the `ngAnimate` module is used.
- *
- * @param {DOMElement} element the external element that will be pinned
- * @param {DOMElement} parentElement the host parent element that will be associated with the external element
- */
- pin: $$animateQueue.pin,
-
- /**
- *
- * @ngdoc method
- * @name $animate#enabled
- * @kind function
- * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This
- * function can be called in four ways:
- *
- * ```js
- * // returns true or false
- * $animate.enabled();
- *
- * // changes the enabled state for all animations
- * $animate.enabled(false);
- * $animate.enabled(true);
- *
- * // returns true or false if animations are enabled for an element
- * $animate.enabled(element);
- *
- * // changes the enabled state for an element and its children
- * $animate.enabled(element, true);
- * $animate.enabled(element, false);
- * ```
- *
- * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state
- * @param {boolean=} enabled whether or not the animations will be enabled for the element
- *
- * @return {boolean} whether or not animations are enabled
- */
- enabled: $$animateQueue.enabled,
-
- /**
- * @ngdoc method
- * @name $animate#cancel
- * @kind function
- * @description Cancels the provided animation.
- *
- * @param {Promise} animationPromise The animation promise that is returned when an animation is started.
- */
- cancel: function(runner) {
- runner.end && runner.end();
- },
-
- /**
- *
- * @ngdoc method
- * @name $animate#enter
- * @kind function
- * @description Inserts the element into the DOM either after the `after` element (if provided) or
- * as the first child within the `parent` element and then triggers an animation.
- * A promise is returned that will be resolved during the next digest once the animation
- * has completed.
- *
- * @param {DOMElement} element the element which will be inserted into the DOM
- * @param {DOMElement} parent the parent element which will append the element as
- * a child (so long as the after element is not present)
- * @param {DOMElement=} after the sibling element after which the element will be appended
- * @param {object=} options an optional collection of options/styles that will be applied to the element
- *
- * @return {Promise} the animation callback promise
- */
- enter: function(element, parent, after, options) {
- parent = parent && jqLite(parent);
- after = after && jqLite(after);
- parent = parent || after.parent();
- domInsert(element, parent, after);
- return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));
- },
-
- /**
- *
- * @ngdoc method
- * @name $animate#move
- * @kind function
- * @description Inserts (moves) the element into its new position in the DOM either after
- * the `after` element (if provided) or as the first child within the `parent` element
- * and then triggers an animation. A promise is returned that will be resolved
- * during the next digest once the animation has completed.
- *
- * @param {DOMElement} element the element which will be moved into the new DOM position
- * @param {DOMElement} parent the parent element which will append the element as
- * a child (so long as the after element is not present)
- * @param {DOMElement=} after the sibling element after which the element will be appended
- * @param {object=} options an optional collection of options/styles that will be applied to the element
- *
- * @return {Promise} the animation callback promise
- */
- move: function(element, parent, after, options) {
- parent = parent && jqLite(parent);
- after = after && jqLite(after);
- parent = parent || after.parent();
- domInsert(element, parent, after);
- return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));
- },
-
- /**
- * @ngdoc method
- * @name $animate#leave
- * @kind function
- * @description Triggers an animation and then removes the element from the DOM.
- * When the function is called a promise is returned that will be resolved during the next
- * digest once the animation has completed.
- *
- * @param {DOMElement} element the element which will be removed from the DOM
- * @param {object=} options an optional collection of options/styles that will be applied to the element
- *
- * @return {Promise} the animation callback promise
- */
- leave: function(element, options) {
- return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {
- element.remove();
- });
- },
-
- /**
- * @ngdoc method
- * @name $animate#addClass
- * @kind function
- *
- * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon
- * execution, the addClass operation will only be handled after the next digest and it will not trigger an
- * animation if element already contains the CSS class or if the class is removed at a later step.
- * Note that class-based animations are treated differently compared to structural animations
- * (like enter, move and leave) since the CSS classes may be added/removed at different points
- * depending if CSS or JavaScript animations are used.
- *
- * @param {DOMElement} element the element which the CSS classes will be applied to
- * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
- * @param {object=} options an optional collection of options/styles that will be applied to the element
- *
- * @return {Promise} the animation callback promise
- */
- addClass: function(element, className, options) {
- options = prepareAnimateOptions(options);
- options.addClass = mergeClasses(options.addclass, className);
- return $$animateQueue.push(element, 'addClass', options);
- },
-
- /**
- * @ngdoc method
- * @name $animate#removeClass
- * @kind function
- *
- * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon
- * execution, the removeClass operation will only be handled after the next digest and it will not trigger an
- * animation if element does not contain the CSS class or if the class is added at a later step.
- * Note that class-based animations are treated differently compared to structural animations
- * (like enter, move and leave) since the CSS classes may be added/removed at different points
- * depending if CSS or JavaScript animations are used.
- *
- * @param {DOMElement} element the element which the CSS classes will be applied to
- * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
- * @param {object=} options an optional collection of options/styles that will be applied to the element
- *
- * @return {Promise} the animation callback promise
- */
- removeClass: function(element, className, options) {
- options = prepareAnimateOptions(options);
- options.removeClass = mergeClasses(options.removeClass, className);
- return $$animateQueue.push(element, 'removeClass', options);
- },
-
- /**
- * @ngdoc method
- * @name $animate#setClass
- * @kind function
- *
- * @description Performs both the addition and removal of a CSS classes on an element and (during the process)
- * triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and
- * `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has
- * passed. Note that class-based animations are treated differently compared to structural animations
- * (like enter, move and leave) since the CSS classes may be added/removed at different points
- * depending if CSS or JavaScript animations are used.
- *
- * @param {DOMElement} element the element which the CSS classes will be applied to
- * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
- * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
- * @param {object=} options an optional collection of options/styles that will be applied to the element
- *
- * @return {Promise} the animation callback promise
- */
- setClass: function(element, add, remove, options) {
- options = prepareAnimateOptions(options);
- options.addClass = mergeClasses(options.addClass, add);
- options.removeClass = mergeClasses(options.removeClass, remove);
- return $$animateQueue.push(element, 'setClass', options);
- },
-
- /**
- * @ngdoc method
- * @name $animate#animate
- * @kind function
- *
- * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
- * If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take
- * on the provided styles. For example, if a transition animation is set for the given classNamem, then the provided `from` and
- * `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding
- * style in `to`, the style in `from` is applied immediately, and no animation is run.
- * If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate`
- * method (or as part of the `options` parameter):
- *
- * ```js
- * ngModule.animation('.my-inline-animation', function() {
- * return {
- * animate : function(element, from, to, done, options) {
- * //animation
- * done();
- * }
- * }
- * });
- * ```
- *
- * @param {DOMElement} element the element which the CSS styles will be applied to
- * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
- * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
- * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
- * this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
- * (Note that if no animation is detected then this value will not be applied to the element.)
- * @param {object=} options an optional collection of options/styles that will be applied to the element
- *
- * @return {Promise} the animation callback promise
- */
- animate: function(element, from, to, className, options) {
- options = prepareAnimateOptions(options);
- options.from = options.from ? extend(options.from, from) : from;
- options.to = options.to ? extend(options.to, to) : to;
-
- className = className || 'ng-inline-animate';
- options.tempClasses = mergeClasses(options.tempClasses, className);
- return $$animateQueue.push(element, 'animate', options);
- }
- };
- }];
-}];
-
-var $$AnimateAsyncRunFactoryProvider = function() {
- this.$get = ['$$rAF', function($$rAF) {
- var waitQueue = [];
-
- function waitForTick(fn) {
- waitQueue.push(fn);
- if (waitQueue.length > 1) return;
- $$rAF(function() {
- for (var i = 0; i < waitQueue.length; i++) {
- waitQueue[i]();
- }
- waitQueue = [];
- });
- }
-
- return function() {
- var passed = false;
- waitForTick(function() {
- passed = true;
- });
- return function(callback) {
- passed ? callback() : waitForTick(callback);
- };
- };
- }];
-};
-
-var $$AnimateRunnerFactoryProvider = function() {
- this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout',
- function($q, $sniffer, $$animateAsyncRun, $document, $timeout) {
-
- var INITIAL_STATE = 0;
- var DONE_PENDING_STATE = 1;
- var DONE_COMPLETE_STATE = 2;
-
- AnimateRunner.chain = function(chain, callback) {
- var index = 0;
-
- next();
- function next() {
- if (index === chain.length) {
- callback(true);
- return;
- }
-
- chain[index](function(response) {
- if (response === false) {
- callback(false);
- return;
- }
- index++;
- next();
- });
- }
- };
-
- AnimateRunner.all = function(runners, callback) {
- var count = 0;
- var status = true;
- forEach(runners, function(runner) {
- runner.done(onProgress);
- });
-
- function onProgress(response) {
- status = status && response;
- if (++count === runners.length) {
- callback(status);
- }
- }
- };
-
- function AnimateRunner(host) {
- this.setHost(host);
-
- var rafTick = $$animateAsyncRun();
- var timeoutTick = function(fn) {
- $timeout(fn, 0, false);
- };
-
- this._doneCallbacks = [];
- this._tick = function(fn) {
- var doc = $document[0];
-
- // the document may not be ready or attached
- // to the module for some internal tests
- if (doc && doc.hidden) {
- timeoutTick(fn);
- } else {
- rafTick(fn);
- }
- };
- this._state = 0;
- }
-
- AnimateRunner.prototype = {
- setHost: function(host) {
- this.host = host || {};
- },
-
- done: function(fn) {
- if (this._state === DONE_COMPLETE_STATE) {
- fn();
- } else {
- this._doneCallbacks.push(fn);
- }
- },
-
- progress: noop,
-
- getPromise: function() {
- if (!this.promise) {
- var self = this;
- this.promise = $q(function(resolve, reject) {
- self.done(function(status) {
- status === false ? reject() : resolve();
- });
- });
- }
- return this.promise;
- },
-
- then: function(resolveHandler, rejectHandler) {
- return this.getPromise().then(resolveHandler, rejectHandler);
- },
-
- 'catch': function(handler) {
- return this.getPromise()['catch'](handler);
- },
-
- 'finally': function(handler) {
- return this.getPromise()['finally'](handler);
- },
-
- pause: function() {
- if (this.host.pause) {
- this.host.pause();
- }
- },
-
- resume: function() {
- if (this.host.resume) {
- this.host.resume();
- }
- },
-
- end: function() {
- if (this.host.end) {
- this.host.end();
- }
- this._resolve(true);
- },
-
- cancel: function() {
- if (this.host.cancel) {
- this.host.cancel();
- }
- this._resolve(false);
- },
-
- complete: function(response) {
- var self = this;
- if (self._state === INITIAL_STATE) {
- self._state = DONE_PENDING_STATE;
- self._tick(function() {
- self._resolve(response);
- });
- }
- },
-
- _resolve: function(response) {
- if (this._state !== DONE_COMPLETE_STATE) {
- forEach(this._doneCallbacks, function(fn) {
- fn(response);
- });
- this._doneCallbacks.length = 0;
- this._state = DONE_COMPLETE_STATE;
- }
- }
- };
-
- return AnimateRunner;
- }];
-};
-
-/**
- * @ngdoc service
- * @name $animateCss
- * @kind object
- *
- * @description
- * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included,
- * then the `$animateCss` service will actually perform animations.
- *
- * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
- */
-var $CoreAnimateCssProvider = function() {
- this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) {
-
- return function(element, initialOptions) {
- // all of the animation functions should create
- // a copy of the options data, however, if a
- // parent service has already created a copy then
- // we should stick to using that
- var options = initialOptions || {};
- if (!options.$$prepared) {
- options = copy(options);
- }
-
- // there is no point in applying the styles since
- // there is no animation that goes on at all in
- // this version of $animateCss.
- if (options.cleanupStyles) {
- options.from = options.to = null;
- }
-
- if (options.from) {
- element.css(options.from);
- options.from = null;
- }
-
- /* jshint newcap: false */
- var closed, runner = new $$AnimateRunner();
- return {
- start: run,
- end: run
- };
-
- function run() {
- $$rAF(function() {
- applyAnimationContents();
- if (!closed) {
- runner.complete();
- }
- closed = true;
- });
- return runner;
- }
-
- function applyAnimationContents() {
- if (options.addClass) {
- element.addClass(options.addClass);
- options.addClass = null;
- }
- if (options.removeClass) {
- element.removeClass(options.removeClass);
- options.removeClass = null;
- }
- if (options.to) {
- element.css(options.to);
- options.to = null;
- }
- }
- };
- }];
-};
-
-/* global stripHash: true */
-
-/**
- * ! This is a private undocumented service !
- *
- * @name $browser
- * @requires $log
- * @description
- * This object has two goals:
- *
- * - hide all the global state in the browser caused by the window object
- * - abstract away all the browser specific features and inconsistencies
- *
- * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
- * service, which can be used for convenient testing of the application without the interaction with
- * the real browser apis.
- */
-/**
- * @param {object} window The global window object.
- * @param {object} document jQuery wrapped document.
- * @param {object} $log window.console or an object with the same interface.
- * @param {object} $sniffer $sniffer service
- */
-function Browser(window, document, $log, $sniffer) {
- var self = this,
- rawDocument = document[0],
- location = window.location,
- history = window.history,
- setTimeout = window.setTimeout,
- clearTimeout = window.clearTimeout,
- pendingDeferIds = {};
-
- self.isMock = false;
-
- var outstandingRequestCount = 0;
- var outstandingRequestCallbacks = [];
-
- // TODO(vojta): remove this temporary api
- self.$$completeOutstandingRequest = completeOutstandingRequest;
- self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
-
- /**
- * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
- * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
- */
- function completeOutstandingRequest(fn) {
- try {
- fn.apply(null, sliceArgs(arguments, 1));
- } finally {
- outstandingRequestCount--;
- if (outstandingRequestCount === 0) {
- while (outstandingRequestCallbacks.length) {
- try {
- outstandingRequestCallbacks.pop()();
- } catch (e) {
- $log.error(e);
- }
- }
- }
- }
- }
-
- function getHash(url) {
- var index = url.indexOf('#');
- return index === -1 ? '' : url.substr(index);
- }
-
- /**
- * @private
- * Note: this method is used only by scenario runner
- * TODO(vojta): prefix this method with $$ ?
- * @param {function()} callback Function that will be called when no outstanding request
- */
- self.notifyWhenNoOutstandingRequests = function(callback) {
- if (outstandingRequestCount === 0) {
- callback();
- } else {
- outstandingRequestCallbacks.push(callback);
- }
- };
-
- //////////////////////////////////////////////////////////////
- // URL API
- //////////////////////////////////////////////////////////////
-
- var cachedState, lastHistoryState,
- lastBrowserUrl = location.href,
- baseElement = document.find('base'),
- pendingLocation = null;
-
- cacheState();
- lastHistoryState = cachedState;
-
- /**
- * @name $browser#url
- *
- * @description
- * GETTER:
- * Without any argument, this method just returns current value of location.href.
- *
- * SETTER:
- * With at least one argument, this method sets url to new value.
- * If html5 history api supported, pushState/replaceState is used, otherwise
- * location.href/location.replace is used.
- * Returns its own instance to allow chaining
- *
- * NOTE: this api is intended for use only by the $location service. Please use the
- * {@link ng.$location $location service} to change url.
- *
- * @param {string} url New url (when used as setter)
- * @param {boolean=} replace Should new url replace current history record?
- * @param {object=} state object to use with pushState/replaceState
- */
- self.url = function(url, replace, state) {
- // In modern browsers `history.state` is `null` by default; treating it separately
- // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
- // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
- if (isUndefined(state)) {
- state = null;
- }
-
- // Android Browser BFCache causes location, history reference to become stale.
- if (location !== window.location) location = window.location;
- if (history !== window.history) history = window.history;
-
- // setter
- if (url) {
- var sameState = lastHistoryState === state;
-
- // Don't change anything if previous and current URLs and states match. This also prevents
- // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
- // See https://github.com/angular/angular.js/commit/ffb2701
- if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
- return self;
- }
- var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
- lastBrowserUrl = url;
- lastHistoryState = state;
- // Don't use history API if only the hash changed
- // due to a bug in IE10/IE11 which leads
- // to not firing a `hashchange` nor `popstate` event
- // in some cases (see #9143).
- if ($sniffer.history && (!sameBase || !sameState)) {
- history[replace ? 'replaceState' : 'pushState'](state, '', url);
- cacheState();
- // Do the assignment again so that those two variables are referentially identical.
- lastHistoryState = cachedState;
- } else {
- if (!sameBase || pendingLocation) {
- pendingLocation = url;
- }
- if (replace) {
- location.replace(url);
- } else if (!sameBase) {
- location.href = url;
- } else {
- location.hash = getHash(url);
- }
- if (location.href !== url) {
- pendingLocation = url;
- }
- }
- return self;
- // getter
- } else {
- // - pendingLocation is needed as browsers don't allow to read out
- // the new location.href if a reload happened or if there is a bug like in iOS 9 (see
- // https://openradar.appspot.com/22186109).
- // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
- return pendingLocation || location.href.replace(/%27/g,"'");
- }
- };
-
- /**
- * @name $browser#state
- *
- * @description
- * This method is a getter.
- *
- * Return history.state or null if history.state is undefined.
- *
- * @returns {object} state
- */
- self.state = function() {
- return cachedState;
- };
-
- var urlChangeListeners = [],
- urlChangeInit = false;
-
- function cacheStateAndFireUrlChange() {
- pendingLocation = null;
- cacheState();
- fireUrlChange();
- }
-
- function getCurrentState() {
- try {
- return history.state;
- } catch (e) {
- // MSIE can reportedly throw when there is no state (UNCONFIRMED).
- }
- }
-
- // This variable should be used *only* inside the cacheState function.
- var lastCachedState = null;
- function cacheState() {
- // This should be the only place in $browser where `history.state` is read.
- cachedState = getCurrentState();
- cachedState = isUndefined(cachedState) ? null : cachedState;
-
- // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
- if (equals(cachedState, lastCachedState)) {
- cachedState = lastCachedState;
- }
- lastCachedState = cachedState;
- }
-
- function fireUrlChange() {
- if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
- return;
- }
-
- lastBrowserUrl = self.url();
- lastHistoryState = cachedState;
- forEach(urlChangeListeners, function(listener) {
- listener(self.url(), cachedState);
- });
- }
-
- /**
- * @name $browser#onUrlChange
- *
- * @description
- * Register callback function that will be called, when url changes.
- *
- * It's only called when the url is changed from outside of angular:
- * - user types different url into address bar
- * - user clicks on history (forward/back) button
- * - user clicks on a link
- *
- * It's not called when url is changed by $browser.url() method
- *
- * The listener gets called with new url as parameter.
- *
- * NOTE: this api is intended for use only by the $location service. Please use the
- * {@link ng.$location $location service} to monitor url changes in angular apps.
- *
- * @param {function(string)} listener Listener function to be called when url changes.
- * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
- */
- self.onUrlChange = function(callback) {
- // TODO(vojta): refactor to use node's syntax for events
- if (!urlChangeInit) {
- // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
- // don't fire popstate when user change the address bar and don't fire hashchange when url
- // changed by push/replaceState
-
- // html5 history api - popstate event
- if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
- // hashchange event
- jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
-
- urlChangeInit = true;
- }
-
- urlChangeListeners.push(callback);
- return callback;
- };
-
- /**
- * @private
- * Remove popstate and hashchange handler from window.
- *
- * NOTE: this api is intended for use only by $rootScope.
- */
- self.$$applicationDestroyed = function() {
- jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);
- };
-
- /**
- * Checks whether the url has changed outside of Angular.
- * Needs to be exported to be able to check for changes that have been done in sync,
- * as hashchange/popstate events fire in async.
- */
- self.$$checkUrlChange = fireUrlChange;
-
- //////////////////////////////////////////////////////////////
- // Misc API
- //////////////////////////////////////////////////////////////
-
- /**
- * @name $browser#baseHref
- *
- * @description
- * Returns current
- * (always relative - without domain)
- *
- * @returns {string} The current base href
- */
- self.baseHref = function() {
- var href = baseElement.attr('href');
- return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
- };
-
- /**
- * @name $browser#defer
- * @param {function()} fn A function, who's execution should be deferred.
- * @param {number=} [delay=0] of milliseconds to defer the function execution.
- * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
- *
- * @description
- * Executes a fn asynchronously via `setTimeout(fn, delay)`.
- *
- * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
- * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
- * via `$browser.defer.flush()`.
- *
- */
- self.defer = function(fn, delay) {
- var timeoutId;
- outstandingRequestCount++;
- timeoutId = setTimeout(function() {
- delete pendingDeferIds[timeoutId];
- completeOutstandingRequest(fn);
- }, delay || 0);
- pendingDeferIds[timeoutId] = true;
- return timeoutId;
- };
-
-
- /**
- * @name $browser#defer.cancel
- *
- * @description
- * Cancels a deferred task identified with `deferId`.
- *
- * @param {*} deferId Token returned by the `$browser.defer` function.
- * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
- * canceled.
- */
- self.defer.cancel = function(deferId) {
- if (pendingDeferIds[deferId]) {
- delete pendingDeferIds[deferId];
- clearTimeout(deferId);
- completeOutstandingRequest(noop);
- return true;
- }
- return false;
- };
-
-}
-
-function $BrowserProvider() {
- this.$get = ['$window', '$log', '$sniffer', '$document',
- function($window, $log, $sniffer, $document) {
- return new Browser($window, $document, $log, $sniffer);
- }];
-}
-
-/**
- * @ngdoc service
- * @name $cacheFactory
- *
- * @description
- * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
- * them.
- *
- * ```js
- *
- * var cache = $cacheFactory('cacheId');
- * expect($cacheFactory.get('cacheId')).toBe(cache);
- * expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
- *
- * cache.put("key", "value");
- * cache.put("another key", "another value");
- *
- * // We've specified no options on creation
- * expect(cache.info()).toEqual({id: 'cacheId', size: 2});
- *
- * ```
- *
- *
- * @param {string} cacheId Name or id of the newly created cache.
- * @param {object=} options Options object that specifies the cache behavior. Properties:
- *
- * - `{number=}` `capacity` — turns the cache into LRU cache.
- *
- * @returns {object} Newly created cache object with the following set of methods:
- *
- * - `{object}` `info()` — Returns id, size, and options of cache.
- * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
- * it.
- * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
- * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
- * - `{void}` `removeAll()` — Removes all cached values.
- * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
- *
- * @example
-
-
-
-
-
-
-
-
Cached Values
-
-
- :
-
-
-
-
Cache Info
-
-
- :
-
-
-
-
-
- angular.module('cacheExampleApp', []).
- controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
- $scope.keys = [];
- $scope.cache = $cacheFactory('cacheId');
- $scope.put = function(key, value) {
- if (angular.isUndefined($scope.cache.get(key))) {
- $scope.keys.push(key);
- }
- $scope.cache.put(key, angular.isUndefined(value) ? null : value);
- };
- }]);
-
-
- p {
- margin: 10px 0 3px;
- }
-
-
- */
-function $CacheFactoryProvider() {
-
- this.$get = function() {
- var caches = {};
-
- function cacheFactory(cacheId, options) {
- if (cacheId in caches) {
- throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
- }
-
- var size = 0,
- stats = extend({}, options, {id: cacheId}),
- data = createMap(),
- capacity = (options && options.capacity) || Number.MAX_VALUE,
- lruHash = createMap(),
- freshEnd = null,
- staleEnd = null;
-
- /**
- * @ngdoc type
- * @name $cacheFactory.Cache
- *
- * @description
- * A cache object used to store and retrieve data, primarily used by
- * {@link $http $http} and the {@link ng.directive:script script} directive to cache
- * templates and other data.
- *
- * ```js
- * angular.module('superCache')
- * .factory('superCache', ['$cacheFactory', function($cacheFactory) {
- * return $cacheFactory('super-cache');
- * }]);
- * ```
- *
- * Example test:
- *
- * ```js
- * it('should behave like a cache', inject(function(superCache) {
- * superCache.put('key', 'value');
- * superCache.put('another key', 'another value');
- *
- * expect(superCache.info()).toEqual({
- * id: 'super-cache',
- * size: 2
- * });
- *
- * superCache.remove('another key');
- * expect(superCache.get('another key')).toBeUndefined();
- *
- * superCache.removeAll();
- * expect(superCache.info()).toEqual({
- * id: 'super-cache',
- * size: 0
- * });
- * }));
- * ```
- */
- return caches[cacheId] = {
-
- /**
- * @ngdoc method
- * @name $cacheFactory.Cache#put
- * @kind function
- *
- * @description
- * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
- * retrieved later, and incrementing the size of the cache if the key was not already
- * present in the cache. If behaving like an LRU cache, it will also remove stale
- * entries from the set.
- *
- * It will not insert undefined values into the cache.
- *
- * @param {string} key the key under which the cached data is stored.
- * @param {*} value the value to store alongside the key. If it is undefined, the key
- * will not be stored.
- * @returns {*} the value stored.
- */
- put: function(key, value) {
- if (isUndefined(value)) return;
- if (capacity < Number.MAX_VALUE) {
- var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
-
- refresh(lruEntry);
- }
-
- if (!(key in data)) size++;
- data[key] = value;
-
- if (size > capacity) {
- this.remove(staleEnd.key);
- }
-
- return value;
- },
-
- /**
- * @ngdoc method
- * @name $cacheFactory.Cache#get
- * @kind function
- *
- * @description
- * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
- *
- * @param {string} key the key of the data to be retrieved
- * @returns {*} the value stored.
- */
- get: function(key) {
- if (capacity < Number.MAX_VALUE) {
- var lruEntry = lruHash[key];
-
- if (!lruEntry) return;
-
- refresh(lruEntry);
- }
-
- return data[key];
- },
-
-
- /**
- * @ngdoc method
- * @name $cacheFactory.Cache#remove
- * @kind function
- *
- * @description
- * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
- *
- * @param {string} key the key of the entry to be removed
- */
- remove: function(key) {
- if (capacity < Number.MAX_VALUE) {
- var lruEntry = lruHash[key];
-
- if (!lruEntry) return;
-
- if (lruEntry == freshEnd) freshEnd = lruEntry.p;
- if (lruEntry == staleEnd) staleEnd = lruEntry.n;
- link(lruEntry.n,lruEntry.p);
-
- delete lruHash[key];
- }
-
- if (!(key in data)) return;
-
- delete data[key];
- size--;
- },
-
-
- /**
- * @ngdoc method
- * @name $cacheFactory.Cache#removeAll
- * @kind function
- *
- * @description
- * Clears the cache object of any entries.
- */
- removeAll: function() {
- data = createMap();
- size = 0;
- lruHash = createMap();
- freshEnd = staleEnd = null;
- },
-
-
- /**
- * @ngdoc method
- * @name $cacheFactory.Cache#destroy
- * @kind function
- *
- * @description
- * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
- * removing it from the {@link $cacheFactory $cacheFactory} set.
- */
- destroy: function() {
- data = null;
- stats = null;
- lruHash = null;
- delete caches[cacheId];
- },
-
-
- /**
- * @ngdoc method
- * @name $cacheFactory.Cache#info
- * @kind function
- *
- * @description
- * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
- *
- * @returns {object} an object with the following properties:
- *
- *
**id**: the id of the cache instance
- *
**size**: the number of entries kept in the cache instance
- *
**...**: any additional properties from the options object when creating the
- * cache.
- *
- */
- info: function() {
- return extend({}, stats, {size: size});
- }
- };
-
-
- /**
- * makes the `entry` the freshEnd of the LRU linked list
- */
- function refresh(entry) {
- if (entry != freshEnd) {
- if (!staleEnd) {
- staleEnd = entry;
- } else if (staleEnd == entry) {
- staleEnd = entry.n;
- }
-
- link(entry.n, entry.p);
- link(entry, freshEnd);
- freshEnd = entry;
- freshEnd.n = null;
- }
- }
-
-
- /**
- * bidirectionally links two entries of the LRU linked list
- */
- function link(nextEntry, prevEntry) {
- if (nextEntry != prevEntry) {
- if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
- if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
- }
- }
- }
-
-
- /**
- * @ngdoc method
- * @name $cacheFactory#info
- *
- * @description
- * Get information about all the caches that have been created
- *
- * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
- */
- cacheFactory.info = function() {
- var info = {};
- forEach(caches, function(cache, cacheId) {
- info[cacheId] = cache.info();
- });
- return info;
- };
-
-
- /**
- * @ngdoc method
- * @name $cacheFactory#get
- *
- * @description
- * Get access to a cache object by the `cacheId` used when it was created.
- *
- * @param {string} cacheId Name or id of a cache to access.
- * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
- */
- cacheFactory.get = function(cacheId) {
- return caches[cacheId];
- };
-
-
- return cacheFactory;
- };
-}
-
-/**
- * @ngdoc service
- * @name $templateCache
- *
- * @description
- * The first time a template is used, it is loaded in the template cache for quick retrieval. You
- * can load templates directly into the cache in a `script` tag, or by consuming the
- * `$templateCache` service directly.
- *
- * Adding via the `script` tag:
- *
- * ```html
- *
- * ```
- *
- * **Note:** the `script` tag containing the template does not need to be included in the `head` of
- * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
- * element with ng-app attribute), otherwise the template will be ignored.
- *
- * Adding via the `$templateCache` service:
- *
- * ```js
- * var myApp = angular.module('myApp', []);
- * myApp.run(function($templateCache) {
- * $templateCache.put('templateId.html', 'This is the content of the template');
- * });
- * ```
- *
- * To retrieve the template later, simply use it in your HTML:
- * ```html
- *
- * ```
- *
- * or get it via Javascript:
- * ```js
- * $templateCache.get('templateId.html')
- * ```
- *
- * See {@link ng.$cacheFactory $cacheFactory}.
- *
- */
-function $TemplateCacheProvider() {
- this.$get = ['$cacheFactory', function($cacheFactory) {
- return $cacheFactory('templates');
- }];
-}
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * 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? *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
- *
- * DOM-related variables:
- *
- * - "node" - DOM Node
- * - "element" - DOM Element or Node
- * - "$node" or "$element" - jqLite-wrapped node or element
- *
- *
- * Compiler related stuff:
- *
- * - "linkFn" - linking fn of a single directive
- * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
- * - "childLinkFn" - function that aggregates all linking fns for child nodes of a particular node
- * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
- */
-
-
-/**
- * @ngdoc service
- * @name $compile
- * @kind function
- *
- * @description
- * Compiles an HTML string or DOM into a template and produces a template function, which
- * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
- *
- * The compilation is a process of walking the DOM tree and matching DOM elements to
- * {@link ng.$compileProvider#directive directives}.
- *
- *
- * **Note:** This document is an in-depth reference of all directive options.
- * For a gentle introduction to directives with examples of common use cases,
- * see the {@link guide/directive directive guide}.
- *
- *
- * ## Comprehensive Directive API
- *
- * There are many different options for a directive.
- *
- * The difference resides in the return value of the factory function.
- * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
- * or just the `postLink` function (all other properties will have the default values).
- *
- *
- * **Best Practice:** It's recommended to use the "directive definition object" form.
- *
- * **Note:** Any unspecified options will use the default value. You can see the default values below.
- *
- *
- * Therefore the above can be simplified as:
- *
- * ```js
- * var myModule = angular.module(...);
- *
- * myModule.directive('directiveName', function factory(injectables) {
- * var directiveDefinitionObject = {
- * link: function postLink(scope, iElement, iAttrs) { ... }
- * };
- * return directiveDefinitionObject;
- * // or
- * // return function postLink(scope, iElement, iAttrs) { ... }
- * });
- * ```
- *
- *
- *
- * ### Directive Definition Object
- *
- * The directive definition object provides instructions to the {@link ng.$compile
- * compiler}. The attributes are:
- *
- * #### `multiElement`
- * When this property is set to true, the HTML compiler will collect DOM nodes between
- * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
- * together as the directive elements. It is recommended that this feature be used on directives
- * which are not strictly behavioral (such as {@link ngClick}), and which
- * do not manipulate or replace child nodes (such as {@link ngInclude}).
- *
- * #### `priority`
- * When there are multiple directives defined on a single DOM element, sometimes it
- * is necessary to specify the order in which the directives are applied. The `priority` is used
- * to sort the directives before their `compile` functions get called. Priority is defined as a
- * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
- * are also run in priority order, but post-link functions are run in reverse order. The order
- * of directives with the same priority is undefined. The default priority is `0`.
- *
- * #### `terminal`
- * If set to true then the current `priority` will be the last set of directives
- * which will execute (any directives at the current priority will still execute
- * as the order of execution on same `priority` is undefined). Note that expressions
- * and other directives used in the directive's template will also be excluded from execution.
- *
- * #### `scope`
- * The scope property can be `true`, an object or a falsy value:
- *
- * * **falsy:** No scope will be created for the directive. The directive will use its parent's scope.
- *
- * * **`true`:** A new child scope that prototypically inherits from its parent will be created for
- * the directive's element. If multiple directives on the same element request a new scope,
- * only one new scope is created. The new scope rule does not apply for the root of the template
- * since the root of the template always gets a new scope.
- *
- * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The
- * 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent
- * scope. This is useful when creating reusable components, which should not accidentally read or modify
- * data in the parent scope.
- *
- * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
- * directive's element. These local properties are useful for aliasing values for templates. The keys in
- * the object hash map to the name of the property on the isolate scope; the values define how the property
- * is bound to the parent scope, via matching attributes on the directive's element:
- *
- * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
- * always a string since DOM attributes are strings. If no `attr` name is specified then the
- * attribute name is assumed to be the same as the local name. Given `` and the isolate scope definition `scope: { localName:'@myAttr' }`,
- * the directive's scope property `localName` will reflect the interpolated value of `hello
- * {{name}}`. As the `name` attribute changes so will the `localName` property on the directive's
- * scope. The `name` is read from the parent scope (not the directive's scope).
- *
- * * `=` or `=attr` - set up a bidirectional binding between a local scope property and an expression
- * passed via the attribute `attr`. The expression is evaluated in the context of the parent scope.
- * If no `attr` name is specified then the attribute name is assumed to be the same as the local
- * name. Given `` and the isolate scope definition `scope: {
- * localModel: '=myAttr' }`, the property `localModel` on the directive's scope will reflect the
- * value of `parentModel` on the parent scope. Changes to `parentModel` will be reflected in
- * `localModel` and vice versa. Optional attributes should be marked as such with a question mark:
- * `=?` or `=?attr`. If the binding expression is non-assignable, or if the attribute isn't
- * optional and doesn't exist, an exception ({@link error/$compile/nonassign `$compile:nonassign`})
- * will be thrown upon discovering changes to the local value, since it will be impossible to sync
- * them back to the parent scope. By default, the {@link ng.$rootScope.Scope#$watch `$watch`}
- * method is used for tracking changes, and the equality check is based on object identity.
- * However, if an object literal or an array literal is passed as the binding expression, the
- * equality check is done by value (using the {@link angular.equals} function). It's also possible
- * to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection
- * `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional).
- *
- * * `<` or `` and directive definition of
- * `scope: { localModel:'` and the isolate scope definition `scope: {
- * localFn:'&myAttr' }`, the isolate scope property `localFn` will point to a function wrapper for
- * the `count = count + value` expression. Often it's desirable to pass data from the isolated scope
- * via an expression to the parent scope. This can be done by passing a map of local variable names
- * and values into the expression wrapper fn. For example, if the expression is `increment(amount)`
- * then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`.
- *
- * In general it's possible to apply more than one directive to one element, but there might be limitations
- * depending on the type of scope required by the directives. The following points will help explain these limitations.
- * For simplicity only two directives are taken into account, but it is also applicable for several directives:
- *
- * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope
- * * **child scope** + **no scope** => Both directives will share one single child scope
- * * **child scope** + **child scope** => Both directives will share one single child scope
- * * **isolated scope** + **no scope** => The isolated directive will use it's own created isolated scope. The other directive will use
- * its parent's scope
- * * **isolated scope** + **child scope** => **Won't work!** Only one scope can be related to one element. Therefore these directives cannot
- * be applied to the same element.
- * * **isolated scope** + **isolated scope** => **Won't work!** Only one scope can be related to one element. Therefore these directives
- * cannot be applied to the same element.
- *
- *
- * #### `bindToController`
- * This property is used to bind scope properties directly to the controller. It can be either
- * `true` or an object hash with the same format as the `scope` property. Additionally, a controller
- * alias must be set, either by using `controllerAs: 'myAlias'` or by specifying the alias in the controller
- * definition: `controller: 'myCtrl as myAlias'`.
- *
- * When an isolate scope is used for a directive (see above), `bindToController: true` will
- * allow a component to have its properties bound to the controller, rather than to scope.
- *
- * After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller
- * properties. You can access these bindings once they have been initialized by providing a controller method called
- * `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings
- * initialized.
- *
- *
- * **Deprecation warning:** although bindings for non-ES6 class controllers are currently
- * bound to `this` before the controller constructor is called, this use is now deprecated. Please place initialization
- * code that relies upon bindings inside a `$onInit` method on the controller, instead.
- *
- *
- * It is also possible to set `bindToController` to an object hash with the same format as the `scope` property.
- * This will set up the scope bindings to the controller directly. Note that `scope` can still be used
- * to define which kind of scope is created. By default, no scope is created. Use `scope: {}` to create an isolate
- * scope (useful for component directives).
- *
- * If both `bindToController` and `scope` are defined and have object hashes, `bindToController` overrides `scope`.
- *
- *
- * #### `controller`
- * Controller constructor function. The controller is instantiated before the
- * pre-linking phase and can be accessed by other directives (see
- * `require` attribute). This allows the directives to communicate with each other and augment
- * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
- *
- * * `$scope` - Current scope associated with the element
- * * `$element` - Current element
- * * `$attrs` - Current attributes object for the element
- * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
- * `function([scope], cloneLinkingFn, futureParentElement, slotName)`:
- * * `scope`: (optional) override the scope.
- * * `cloneLinkingFn`: (optional) argument to create clones of the original transcluded content.
- * * `futureParentElement` (optional):
- * * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
- * * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
- * * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
- * and when the `cloneLinkinFn` is passed,
- * as those elements need to created and cloned in a special way when they are defined outside their
- * usual containers (e.g. like `