mirror of
https://github.com/spring-projects/spring-petclinic.git
synced 2025-07-17 21:35:50 +00:00
LH :: Refreshed js library files to angular version 1.3.11
- Added ngResource
This commit is contained in:
parent
756e74f7cc
commit
b8f97b53b9
24 changed files with 10537 additions and 13822 deletions
|
@ -38,12 +38,13 @@
|
|||
|
||||
<!-- build:js({app,.tmp}) scripts/main.js -->
|
||||
<script src="js/lib/angular.js"></script>
|
||||
<script src="js/lib/angular-resource.js"></script>
|
||||
<script src="js/lib/angular-ui-router.js"></script>
|
||||
<script src="js/lib/angular-ui-router-statehelper.js"></script>
|
||||
<script src="js/lib/angular-animate.js"></script>
|
||||
<script src="js/lib/angular-cookies.js"></script>
|
||||
<script src="services/services.js"></script>
|
||||
<script src="components/main/MainController.js"></script>
|
||||
<script src="components/about/AboutController.js"></script>
|
||||
<script src="components/veterinarians/VeterinarianController.js"></script>
|
||||
<script src="components/pets/PetController.js"></script>
|
||||
<script src="components/owners/OwnerController.js"></script>
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
var AboutController = function($scope) {
|
||||
};
|
||||
|
||||
var AboutControllerDeclaration = ['$scope',AboutController];
|
|
@ -1 +0,0 @@
|
|||
<section data-ng-controller="AboutController">This is the about page</section>
|
|
@ -14,7 +14,7 @@
|
|||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
<div id="nav-menu" class="navbar-collapse navbar-left collapse">
|
||||
<ul class="nav navbar-nav navbar-menu" data-ng-if="getSession() != null">
|
||||
<li data-ng-class="$state.is('landing') ? 'active' : ''"><a data-ui-sref="about">Home</a></li>
|
||||
<li data-ng-class="$state.is('landing') ? 'active' : ''"><a data-ui-sref="landing">Home</a></li>
|
||||
<li data-ng-class="$state.is('pets') ? 'active' : ''"><a data-ui-sref="pets">Pets</a></li>
|
||||
<li data-ng-class="$state.is('owners') ? 'active' : ''"><a data-ui-sref="owners">Owners</a></li>
|
||||
<li data-ng-class="$state.is('vets') ? 'active' : ''"><a data-ui-sref="vets">Vets</a></li>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
var MainController = function($scope, $rootScope, $state) {
|
||||
var MainController = ['$scope','$rootScope','$state',function($scope, $rootScope, $state) {
|
||||
|
||||
$scope.getSession = function() {
|
||||
return $scope.session;
|
||||
|
@ -37,7 +37,5 @@ var MainController = function($scope, $rootScope, $state) {
|
|||
$scope.footerText = '© ' + new Date().getFullYear() + ' Pet Clinic, A Spring Framework Demonstration';
|
||||
|
||||
$rootScope.$state = $state;
|
||||
};
|
||||
|
||||
var MainControllerDeclaration = ['$scope','$rootScope','$state',MainController];
|
||||
}];
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
var OwnerController = function($scope) {
|
||||
var OwnerController = ['$scope',function($scope) {
|
||||
$scope.$on('$viewContentLoaded', function(event){
|
||||
$('html, body').animate({
|
||||
scrollTop: $("#owners").offset().top
|
||||
}, 1000);
|
||||
});
|
||||
};
|
||||
|
||||
var OwnerControllerDeclaration = ['$scope',OwnerController];
|
||||
}];
|
|
@ -1,4 +1,4 @@
|
|||
var PetController = function($scope) {
|
||||
var PetController = ['$scope', function($scope) {
|
||||
|
||||
$scope.$on('$viewContentLoaded', function(event){
|
||||
$('html, body').animate({
|
||||
|
@ -6,6 +6,4 @@ var PetController = function($scope) {
|
|||
}, 1000);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
var PetControllerDeclaration = ['$scope',PetController];
|
||||
}];
|
|
@ -1,7 +1,4 @@
|
|||
var VeterinarianController = function ($scope, $http) {
|
||||
$http.get('api/vets').success(function(data) {
|
||||
$scope.veterinarians = data;
|
||||
});
|
||||
var VeterinarianController = ['$scope','$http','Vet', function ($scope, $http, Vet) {
|
||||
|
||||
$scope.$on('$viewContentLoaded', function(event){
|
||||
$('html, body').animate({
|
||||
|
@ -9,6 +6,6 @@ var VeterinarianController = function ($scope, $http) {
|
|||
}, 1000);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
var VeterinarianControllerDeclaration = ['$scope','$http',VeterinarianController];
|
||||
$scope.vets = Vet.query();
|
||||
|
||||
}];
|
|
@ -5,7 +5,7 @@
|
|||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="text-center">
|
||||
<h3 class="section-heading">Our Veterinarians</h3>
|
||||
<p class="section-desc">A small river named Duden flows by their place and supplies it with the necessary regelialia. It is a paradisematic country, in which roasted parts of sentences fly into your mouth.</p>
|
||||
<p class="section-desc">We provide the best medical expertise and care for your fur kids!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
var VisitController = function($scope) {
|
||||
};
|
||||
var VisitController = ['$scope',function($scope) {
|
||||
|
||||
var VisitControllerDeclaration = ['$scope',VisitController];
|
||||
}];
|
|
@ -1,11 +1,4 @@
|
|||
var app = angular.module('spring-petclinic', ['ui.router','ui.router.stateHelper','ngAnimate','ngCookies']);
|
||||
|
||||
app.controller('MainController', MainControllerDeclaration);
|
||||
app.controller('VeterinarianController', VeterinarianControllerDeclaration);
|
||||
app.controller('PetController', PetControllerDeclaration);
|
||||
app.controller('OwnerController', OwnerControllerDeclaration);
|
||||
app.controller('VisitController', VisitControllerDeclaration);
|
||||
app.controller('AboutController', AboutControllerDeclaration);
|
||||
var app = angular.module('spring-petclinic', ['ui.router','ui.router.stateHelper','ngAnimate','ngCookies','ngResource']);
|
||||
|
||||
app.config(['stateHelperProvider','$urlRouterProvider','$urlMatcherFactoryProvider',function(stateHelperProvider,$urlRouterProvider,$urlMatcherFactoryProvider) {
|
||||
|
||||
|
@ -36,3 +29,16 @@ app.config(['stateHelperProvider','$urlRouterProvider','$urlMatcherFactoryProvid
|
|||
});
|
||||
|
||||
} ]);
|
||||
|
||||
/** Controllers **/
|
||||
app.controller('MainController', MainController);
|
||||
app.controller('VeterinarianController', VeterinarianController);
|
||||
app.controller('PetController', PetController);
|
||||
app.controller('OwnerController', OwnerController);
|
||||
app.controller('VisitController', VisitController);
|
||||
|
||||
/** Services **/
|
||||
app.factory('Owner', Owner);
|
||||
app.factory('Pet', Pet);
|
||||
app.factory('Vet', Vet);
|
||||
app.factory('Visit', Visit);
|
1447
src/main/webapp/js/lib/angular-animate.js
vendored
1447
src/main/webapp/js/lib/angular-animate.js
vendored
File diff suppressed because it is too large
Load diff
8
src/main/webapp/js/lib/angular-cookies.js
vendored
8
src/main/webapp/js/lib/angular-cookies.js
vendored
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* @license AngularJS v1.3.0-build.3242+sha.6a96a82
|
||||
* @license AngularJS v1.3.11
|
||||
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
|
@ -48,7 +48,7 @@ angular.module('ngCookies', ['ng']).
|
|||
* }]);
|
||||
* ```
|
||||
*/
|
||||
factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) {
|
||||
factory('$cookies', ['$rootScope', '$browser', function($rootScope, $browser) {
|
||||
var cookies = {},
|
||||
lastCookies = {},
|
||||
lastBrowserCookies,
|
||||
|
@ -95,7 +95,7 @@ angular.module('ngCookies', ['ng']).
|
|||
}
|
||||
|
||||
//update all cookies updated in $cookies
|
||||
for(name in cookies) {
|
||||
for (name in cookies) {
|
||||
value = cookies[name];
|
||||
if (!angular.isString(value)) {
|
||||
value = '' + value;
|
||||
|
@ -108,7 +108,7 @@ angular.module('ngCookies', ['ng']).
|
|||
}
|
||||
|
||||
//verify what was actually stored
|
||||
if (updated){
|
||||
if (updated) {
|
||||
updated = false;
|
||||
browserCookies = $browser.cookies();
|
||||
|
||||
|
|
366
src/main/webapp/js/lib/angular-file-upload-shim.js
vendored
366
src/main/webapp/js/lib/angular-file-upload-shim.js
vendored
|
@ -1,366 +0,0 @@
|
|||
/**!
|
||||
* AngularJS file upload/drop directive with progress and abort
|
||||
* FileAPI Flash shim for old browsers not supporting FormData
|
||||
* @author Danial <danial.farid@gmail.com>
|
||||
* @version <%= pkg.version %>
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
||||
var hasFlash = function() {
|
||||
try {
|
||||
var fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
|
||||
if (fo) return true;
|
||||
} catch(e) {
|
||||
if (navigator.mimeTypes['application/x-shockwave-flash'] != undefined) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function patchXHR(fnName, newFn) {
|
||||
window.XMLHttpRequest.prototype[fnName] = newFn(window.XMLHttpRequest.prototype[fnName]);
|
||||
};
|
||||
|
||||
if ((window.XMLHttpRequest && !window.FormData) || (window.FileAPI && FileAPI.forceLoad)) {
|
||||
var initializeUploadListener = function(xhr) {
|
||||
if (!xhr.__listeners) {
|
||||
if (!xhr.upload) xhr.upload = {};
|
||||
xhr.__listeners = [];
|
||||
var origAddEventListener = xhr.upload.addEventListener;
|
||||
xhr.upload.addEventListener = function(t, fn, b) {
|
||||
xhr.__listeners[t] = fn;
|
||||
origAddEventListener && origAddEventListener.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
patchXHR('open', function(orig) {
|
||||
return function(m, url, b) {
|
||||
initializeUploadListener(this);
|
||||
this.__url = url;
|
||||
try {
|
||||
orig.apply(this, [m, url, b]);
|
||||
} catch (e) {
|
||||
if (e.message.indexOf('Access is denied') > -1) {
|
||||
orig.apply(this, [m, '_fix_for_ie_crossdomain__', b]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
patchXHR('getResponseHeader', function(orig) {
|
||||
return function(h) {
|
||||
return this.__fileApiXHR && this.__fileApiXHR.getResponseHeader ? this.__fileApiXHR.getResponseHeader(h) : (orig == null ? null : orig.apply(this, [h]));
|
||||
};
|
||||
});
|
||||
|
||||
patchXHR('getAllResponseHeaders', function(orig) {
|
||||
return function() {
|
||||
return this.__fileApiXHR && this.__fileApiXHR.getAllResponseHeaders ? this.__fileApiXHR.getAllResponseHeaders() : (orig == null ? null : orig.apply(this));
|
||||
}
|
||||
});
|
||||
|
||||
patchXHR('abort', function(orig) {
|
||||
return function() {
|
||||
return this.__fileApiXHR && this.__fileApiXHR.abort ? this.__fileApiXHR.abort() : (orig == null ? null : orig.apply(this));
|
||||
}
|
||||
});
|
||||
|
||||
patchXHR('setRequestHeader', function(orig) {
|
||||
return function(header, value) {
|
||||
if (header === '__setXHR_') {
|
||||
initializeUploadListener(this);
|
||||
var val = value(this);
|
||||
// fix for angular < 1.2.0
|
||||
if (val instanceof Function) {
|
||||
val(this);
|
||||
}
|
||||
} else {
|
||||
this.__requestHeaders = this.__requestHeaders || {};
|
||||
this.__requestHeaders[header] = value;
|
||||
orig.apply(this, arguments);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function redefineProp(xhr, prop, fn) {
|
||||
try {
|
||||
Object.defineProperty(xhr, prop, {get: fn});
|
||||
} catch (e) {/*ignore*/}
|
||||
}
|
||||
|
||||
patchXHR('send', function(orig) {
|
||||
return function() {
|
||||
var xhr = this;
|
||||
if (arguments[0] && arguments[0].__isFileAPIShim) {
|
||||
var formData = arguments[0];
|
||||
var config = {
|
||||
url: xhr.__url,
|
||||
jsonp: false, //removes the callback form param
|
||||
cache: true, //removes the ?fileapiXXX in the url
|
||||
complete: function(err, fileApiXHR) {
|
||||
xhr.__completed = true;
|
||||
if (!err && xhr.__listeners['load'])
|
||||
xhr.__listeners['load']({type: 'load', loaded: xhr.__loaded, total: xhr.__total, target: xhr, lengthComputable: true});
|
||||
if (!err && xhr.__listeners['loadend'])
|
||||
xhr.__listeners['loadend']({type: 'loadend', loaded: xhr.__loaded, total: xhr.__total, target: xhr, lengthComputable: true});
|
||||
if (err === 'abort' && xhr.__listeners['abort'])
|
||||
xhr.__listeners['abort']({type: 'abort', loaded: xhr.__loaded, total: xhr.__total, target: xhr, lengthComputable: true});
|
||||
if (fileApiXHR.status !== undefined) redefineProp(xhr, 'status', function() {return (fileApiXHR.status == 0 && err && err !== 'abort') ? 500 : fileApiXHR.status});
|
||||
if (fileApiXHR.statusText !== undefined) redefineProp(xhr, 'statusText', function() {return fileApiXHR.statusText});
|
||||
redefineProp(xhr, 'readyState', function() {return 4});
|
||||
if (fileApiXHR.response !== undefined) redefineProp(xhr, 'response', function() {return fileApiXHR.response});
|
||||
var resp = fileApiXHR.responseText || (err && fileApiXHR.status == 0 && err !== 'abort' ? err : undefined);
|
||||
redefineProp(xhr, 'responseText', function() {return resp});
|
||||
redefineProp(xhr, 'response', function() {return resp});
|
||||
if (err) redefineProp(xhr, 'err', function() {return err});
|
||||
xhr.__fileApiXHR = fileApiXHR;
|
||||
if (xhr.onreadystatechange) xhr.onreadystatechange();
|
||||
if (xhr.onload) xhr.onload();
|
||||
},
|
||||
fileprogress: function(e) {
|
||||
e.target = xhr;
|
||||
xhr.__listeners['progress'] && xhr.__listeners['progress'](e);
|
||||
xhr.__total = e.total;
|
||||
xhr.__loaded = e.loaded;
|
||||
if (e.total === e.loaded) {
|
||||
// fix flash issue that doesn't call complete if there is no response text from the server
|
||||
var _this = this
|
||||
setTimeout(function() {
|
||||
if (!xhr.__completed) {
|
||||
xhr.getAllResponseHeaders = function(){};
|
||||
_this.complete(null, {status: 204, statusText: 'No Content'});
|
||||
}
|
||||
}, 10000);
|
||||
}
|
||||
},
|
||||
headers: xhr.__requestHeaders
|
||||
}
|
||||
config.data = {};
|
||||
config.files = {}
|
||||
for (var i = 0; i < formData.data.length; i++) {
|
||||
var item = formData.data[i];
|
||||
if (item.val != null && item.val.name != null && item.val.size != null && item.val.type != null) {
|
||||
config.files[item.key] = item.val;
|
||||
} else {
|
||||
config.data[item.key] = item.val;
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
if (!hasFlash()) {
|
||||
throw 'Adode Flash Player need to be installed. To check ahead use "FileAPI.hasFlash"';
|
||||
}
|
||||
xhr.__fileApiXHR = FileAPI.upload(config);
|
||||
}, 1);
|
||||
} else {
|
||||
orig.apply(xhr, arguments);
|
||||
}
|
||||
}
|
||||
});
|
||||
window.XMLHttpRequest.__isFileAPIShim = true;
|
||||
|
||||
var addFlash = function(elem) {
|
||||
if (!hasFlash()) {
|
||||
throw 'Adode Flash Player need to be installed. To check ahead use "FileAPI.hasFlash"';
|
||||
}
|
||||
var el = angular.element(elem);
|
||||
if (!el.attr('disabled')) {
|
||||
if (!el.hasClass('js-fileapi-wrapper') && (el.attr('ng-file-select') != null || el.attr('data-ng-file-select') != null ||
|
||||
(el.attr('ng-file-generated-elem') &&
|
||||
(el.parent().attr('ng-file-select') != null || el.parent().attr('data-ng-file-select') != null)))) {
|
||||
if (FileAPI.wrapInsideDiv) {
|
||||
var wrap = document.createElement('div');
|
||||
wrap.innerHTML = '<div class="js-fileapi-wrapper" style="position:relative; overflow:hidden"></div>';
|
||||
wrap = wrap.firstChild;
|
||||
var parent = elem.parentNode;
|
||||
parent.insertBefore(wrap, elem);
|
||||
parent.removeChild(elem);
|
||||
wrap.appendChild(elem);
|
||||
} else {
|
||||
el.addClass('js-fileapi-wrapper');
|
||||
if (el.attr('ng-file-generated-elem')) {
|
||||
if (el.parent().css('position') === '' || el.parent().css('position') === 'static') {
|
||||
el.parent().css('position', 'relative');
|
||||
}
|
||||
el.css('top', 0).css('bottom', 0).css('left', 0).css('right', 0).css('width', '100%').css('height', '100%').
|
||||
css('padding', 0).css('margin', 0);
|
||||
el.parent().unbind('click', el.parent().__afu_fileClickDelegate__);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
var changeFnWrapper = function(fn) {
|
||||
return function(evt) {
|
||||
var files = FileAPI.getFiles(evt);
|
||||
//just a double check for #233
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
if (files[i].size === undefined) files[i].size = 0;
|
||||
if (files[i].name === undefined) files[i].name = 'file';
|
||||
if (files[i].type === undefined) files[i].type = 'undefined';
|
||||
}
|
||||
if (!evt.target) {
|
||||
evt.target = {};
|
||||
}
|
||||
evt.target.files = files;
|
||||
// if evt.target.files is not writable use helper field
|
||||
if (evt.target.files != files) {
|
||||
evt.__files_ = files;
|
||||
}
|
||||
(evt.__files_ || evt.target.files).item = function(i) {
|
||||
return (evt.__files_ || evt.target.files)[i] || null;
|
||||
}
|
||||
if (fn) fn.apply(this, [evt]);
|
||||
};
|
||||
};
|
||||
var isFileChange = function(elem, e) {
|
||||
return (e.toLowerCase() === 'change' || e.toLowerCase() === 'onchange') && elem.getAttribute('type') == 'file';
|
||||
}
|
||||
if (HTMLInputElement.prototype.addEventListener) {
|
||||
HTMLInputElement.prototype.addEventListener = (function(origAddEventListener) {
|
||||
return function(e, fn, b, d) {
|
||||
if (isFileChange(this, e)) {
|
||||
addFlash(this);
|
||||
origAddEventListener.apply(this, [e, changeFnWrapper(fn), b, d]);
|
||||
} else {
|
||||
origAddEventListener.apply(this, [e, fn, b, d]);
|
||||
}
|
||||
}
|
||||
})(HTMLInputElement.prototype.addEventListener);
|
||||
}
|
||||
if (HTMLInputElement.prototype.attachEvent) {
|
||||
HTMLInputElement.prototype.attachEvent = (function(origAttachEvent) {
|
||||
return function(e, fn) {
|
||||
if (isFileChange(this, e)) {
|
||||
addFlash(this);
|
||||
if (window.jQuery) {
|
||||
// fix for #281 jQuery on IE8
|
||||
angular.element(this).bind('change', changeFnWrapper(null));
|
||||
} else {
|
||||
origAttachEvent.apply(this, [e, changeFnWrapper(fn)]);
|
||||
}
|
||||
} else {
|
||||
origAttachEvent.apply(this, [e, fn]);
|
||||
}
|
||||
}
|
||||
})(HTMLInputElement.prototype.attachEvent);
|
||||
}
|
||||
|
||||
window.FormData = FormData = function() {
|
||||
return {
|
||||
append: function(key, val, name) {
|
||||
this.data.push({
|
||||
key: key,
|
||||
val: val,
|
||||
name: name
|
||||
});
|
||||
},
|
||||
data: [],
|
||||
__isFileAPIShim: true
|
||||
};
|
||||
};
|
||||
|
||||
(function () {
|
||||
//load FileAPI
|
||||
if (!window.FileAPI) {
|
||||
window.FileAPI = {};
|
||||
}
|
||||
if (FileAPI.forceLoad) {
|
||||
FileAPI.html5 = false;
|
||||
}
|
||||
|
||||
if (!FileAPI.upload) {
|
||||
var jsUrl, basePath, script = document.createElement('script'), allScripts = document.getElementsByTagName('script'), i, index, src;
|
||||
if (window.FileAPI.jsUrl) {
|
||||
jsUrl = window.FileAPI.jsUrl;
|
||||
} else if (window.FileAPI.jsPath) {
|
||||
basePath = window.FileAPI.jsPath;
|
||||
} else {
|
||||
for (i = 0; i < allScripts.length; i++) {
|
||||
src = allScripts[i].src;
|
||||
index = src.search(/\/angular\-file\-upload[\-a-zA-z0-9\.]*\.js/)
|
||||
if (index > -1) {
|
||||
basePath = src.substring(0, index + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FileAPI.staticPath == null) FileAPI.staticPath = basePath;
|
||||
script.setAttribute('src', jsUrl || basePath + 'FileAPI.min.js');
|
||||
document.getElementsByTagName('head')[0].appendChild(script);
|
||||
FileAPI.hasFlash = hasFlash();
|
||||
}
|
||||
})();
|
||||
FileAPI.disableFileInput = function(elem, disable) {
|
||||
if (disable) {
|
||||
elem.removeClass('js-fileapi-wrapper')
|
||||
} else {
|
||||
elem.addClass('js-fileapi-wrapper');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!window.FileReader) {
|
||||
window.FileReader = function() {
|
||||
var _this = this, loadStarted = false;
|
||||
this.listeners = {};
|
||||
this.addEventListener = function(type, fn) {
|
||||
_this.listeners[type] = _this.listeners[type] || [];
|
||||
_this.listeners[type].push(fn);
|
||||
};
|
||||
this.removeEventListener = function(type, fn) {
|
||||
_this.listeners[type] && _this.listeners[type].splice(_this.listeners[type].indexOf(fn), 1);
|
||||
};
|
||||
this.dispatchEvent = function(evt) {
|
||||
var list = _this.listeners[evt.type];
|
||||
if (list) {
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
list[i].call(_this, evt);
|
||||
}
|
||||
}
|
||||
};
|
||||
this.onabort = this.onerror = this.onload = this.onloadstart = this.onloadend = this.onprogress = null;
|
||||
|
||||
var constructEvent = function(type, evt) {
|
||||
var e = {type: type, target: _this, loaded: evt.loaded, total: evt.total, error: evt.error};
|
||||
if (evt.result != null) e.target.result = evt.result;
|
||||
return e;
|
||||
};
|
||||
var listener = function(evt) {
|
||||
if (!loadStarted) {
|
||||
loadStarted = true;
|
||||
_this.onloadstart && this.onloadstart(constructEvent('loadstart', evt));
|
||||
}
|
||||
if (evt.type === 'load') {
|
||||
_this.onloadend && _this.onloadend(constructEvent('loadend', evt));
|
||||
var e = constructEvent('load', evt);
|
||||
_this.onload && _this.onload(e);
|
||||
_this.dispatchEvent(e);
|
||||
} else if (evt.type === 'progress') {
|
||||
var e = constructEvent('progress', evt);
|
||||
_this.onprogress && _this.onprogress(e);
|
||||
_this.dispatchEvent(e);
|
||||
} else {
|
||||
var e = constructEvent('error', evt);
|
||||
_this.onerror && _this.onerror(e);
|
||||
_this.dispatchEvent(e);
|
||||
}
|
||||
};
|
||||
this.readAsArrayBuffer = function(file) {
|
||||
FileAPI.readAsBinaryString(file, listener);
|
||||
}
|
||||
this.readAsBinaryString = function(file) {
|
||||
FileAPI.readAsBinaryString(file, listener);
|
||||
}
|
||||
this.readAsDataURL = function(file) {
|
||||
FileAPI.readAsDataURL(file, listener);
|
||||
}
|
||||
this.readAsText = function(file) {
|
||||
FileAPI.readAsText(file, listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
483
src/main/webapp/js/lib/angular-file-upload.js
vendored
483
src/main/webapp/js/lib/angular-file-upload.js
vendored
|
@ -1,483 +0,0 @@
|
|||
/**!
|
||||
* AngularJS file upload/drop directive with progress and abort
|
||||
* @author Danial <danial.farid@gmail.com>
|
||||
* @version <%= pkg.version %>
|
||||
*/
|
||||
(function() {
|
||||
|
||||
function patchXHR(fnName, newFn) {
|
||||
window.XMLHttpRequest.prototype[fnName] = newFn(window.XMLHttpRequest.prototype[fnName]);
|
||||
}
|
||||
|
||||
if (window.XMLHttpRequest && !window.XMLHttpRequest.__isFileAPIShim) {
|
||||
patchXHR('setRequestHeader', function(orig) {
|
||||
return function(header, value) {
|
||||
if (header === '__setXHR_') {
|
||||
var val = value(this);
|
||||
// fix for angular < 1.2.0
|
||||
if (val instanceof Function) {
|
||||
val(this);
|
||||
}
|
||||
} else {
|
||||
orig.apply(this, arguments);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var angularFileUpload = angular.module('angularFileUpload', []);
|
||||
angularFileUpload.version = '<%= pkg.version %>';
|
||||
angularFileUpload.service('$upload', ['$http', '$q', '$timeout', function($http, $q, $timeout) {
|
||||
function sendHttp(config) {
|
||||
config.method = config.method || 'POST';
|
||||
config.headers = config.headers || {};
|
||||
config.transformRequest = config.transformRequest || function(data, headersGetter) {
|
||||
if (window.ArrayBuffer && data instanceof window.ArrayBuffer) {
|
||||
return data;
|
||||
}
|
||||
return $http.defaults.transformRequest[0](data, headersGetter);
|
||||
};
|
||||
var deferred = $q.defer();
|
||||
var promise = deferred.promise;
|
||||
|
||||
config.headers['__setXHR_'] = function() {
|
||||
return function(xhr) {
|
||||
if (!xhr) return;
|
||||
config.__XHR = xhr;
|
||||
config.xhrFn && config.xhrFn(xhr);
|
||||
xhr.upload.addEventListener('progress', function(e) {
|
||||
e.config = config;
|
||||
deferred.notify ? deferred.notify(e) : promise.progress_fn && $timeout(function(){promise.progress_fn(e)});
|
||||
}, false);
|
||||
//fix for firefox not firing upload progress end, also IE8-9
|
||||
xhr.upload.addEventListener('load', function(e) {
|
||||
if (e.lengthComputable) {
|
||||
e.config = config;
|
||||
deferred.notify ? deferred.notify(e) : promise.progress_fn && $timeout(function(){promise.progress_fn(e)});
|
||||
}
|
||||
}, false);
|
||||
};
|
||||
};
|
||||
|
||||
$http(config).then(function(r){deferred.resolve(r)}, function(e){deferred.reject(e)}, function(n){deferred.notify(n)});
|
||||
|
||||
promise.success = function(fn) {
|
||||
promise.then(function(response) {
|
||||
fn(response.data, response.status, response.headers, config);
|
||||
});
|
||||
return promise;
|
||||
};
|
||||
|
||||
promise.error = function(fn) {
|
||||
promise.then(null, function(response) {
|
||||
fn(response.data, response.status, response.headers, config);
|
||||
});
|
||||
return promise;
|
||||
};
|
||||
|
||||
promise.progress = function(fn) {
|
||||
promise.progress_fn = fn;
|
||||
promise.then(null, null, function(update) {
|
||||
fn(update);
|
||||
});
|
||||
return promise;
|
||||
};
|
||||
promise.abort = function() {
|
||||
if (config.__XHR) {
|
||||
$timeout(function() {
|
||||
config.__XHR.abort();
|
||||
});
|
||||
}
|
||||
return promise;
|
||||
};
|
||||
promise.xhr = function(fn) {
|
||||
config.xhrFn = (function(origXhrFn) {
|
||||
return function() {
|
||||
origXhrFn && origXhrFn.apply(promise, arguments);
|
||||
fn.apply(promise, arguments);
|
||||
}
|
||||
})(config.xhrFn);
|
||||
return promise;
|
||||
};
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
this.upload = function(config) {
|
||||
config.headers = config.headers || {};
|
||||
config.headers['Content-Type'] = undefined;
|
||||
config.transformRequest = config.transformRequest || $http.defaults.transformRequest;
|
||||
var formData = new FormData();
|
||||
var origTransformRequest = config.transformRequest;
|
||||
var origData = config.data;
|
||||
config.transformRequest = function(formData, headerGetter) {
|
||||
if (origData) {
|
||||
if (config.formDataAppender) {
|
||||
for (var key in origData) {
|
||||
var val = origData[key];
|
||||
config.formDataAppender(formData, key, val);
|
||||
}
|
||||
} else {
|
||||
for (var key in origData) {
|
||||
var val = origData[key];
|
||||
if (typeof origTransformRequest == 'function') {
|
||||
val = origTransformRequest(val, headerGetter);
|
||||
} else {
|
||||
for (var i = 0; i < origTransformRequest.length; i++) {
|
||||
var transformFn = origTransformRequest[i];
|
||||
if (typeof transformFn == 'function') {
|
||||
val = transformFn(val, headerGetter);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (val != undefined) formData.append(key, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.file != null) {
|
||||
var fileFormName = config.fileFormDataName || 'file';
|
||||
|
||||
if (Object.prototype.toString.call(config.file) === '[object Array]') {
|
||||
var isFileFormNameString = Object.prototype.toString.call(fileFormName) === '[object String]';
|
||||
for (var i = 0; i < config.file.length; i++) {
|
||||
formData.append(isFileFormNameString ? fileFormName : fileFormName[i], config.file[i],
|
||||
(config.fileName && config.fileName[i]) || config.file[i].name);
|
||||
}
|
||||
} else {
|
||||
formData.append(fileFormName, config.file, config.fileName || config.file.name);
|
||||
}
|
||||
}
|
||||
return formData;
|
||||
};
|
||||
|
||||
config.data = formData;
|
||||
|
||||
return sendHttp(config);
|
||||
};
|
||||
|
||||
this.http = function(config) {
|
||||
return sendHttp(config);
|
||||
};
|
||||
}]);
|
||||
|
||||
angularFileUpload.directive('ngFileSelect', [ '$parse', '$timeout', function($parse, $timeout) { return {
|
||||
restrict: 'AEC',
|
||||
require:'?ngModel',
|
||||
scope: {
|
||||
fileModel: '=ngModel',
|
||||
change: '&ngFileChange',
|
||||
select : '&ngFileSelect',
|
||||
resetOnClick: '&resetOnClick',
|
||||
multiple: '&ngMultiple',
|
||||
accept: '&ngAccept'
|
||||
},
|
||||
link: function(scope, elem, attr, ngModel) {
|
||||
handleFileSelect(scope, elem, attr, ngModel, $parse, $timeout);
|
||||
}
|
||||
}}]);
|
||||
|
||||
function handleFileSelect(scope, elem, attr, ngModel, $parse, $timeout) {
|
||||
if (scope.multiple()) {
|
||||
elem.attr('multiple', 'true');
|
||||
attr['multiple'] = 'true';
|
||||
}
|
||||
var accept = scope.accept();
|
||||
if (accept) {
|
||||
elem.attr('accept', accept);
|
||||
attr['accept'] = accept;
|
||||
}
|
||||
if (elem[0].tagName.toLowerCase() !== 'input' || (elem.attr('type') && elem.attr('type').toLowerCase()) !== 'file') {
|
||||
var fileElem = angular.element('<input type="file">')
|
||||
if (attr['multiple']) fileElem.attr('multiple', attr['multiple']);
|
||||
if (attr['accept']) fileElem.attr('accept', attr['accept']);
|
||||
fileElem.css('width', '1px').css('height', '1px').css('opacity', 0).css('position', 'absolute').css('filter', 'alpha(opacity=0)')
|
||||
.css('padding', 0).css('margin', 0).css('overflow', 'hidden').attr('tabindex', '-1').attr('ng-file-generated-elem', true);
|
||||
elem.append(fileElem);
|
||||
elem.__afu_fileClickDelegate__ = function() {
|
||||
fileElem[0].click();
|
||||
};
|
||||
elem.bind('click', elem.__afu_fileClickDelegate__);
|
||||
elem.css('overflow', 'hidden');
|
||||
elem = fileElem;
|
||||
}
|
||||
if (scope.resetOnClick() != false) {
|
||||
elem.bind('click', function(evt) {
|
||||
if (elem[0].value) {
|
||||
updateModel([], attr, ngModel, scope, evt);
|
||||
}
|
||||
elem[0].value = null;
|
||||
});
|
||||
}
|
||||
if (ngModel) {
|
||||
scope.$parent.$watch(attr['ngModel'], function(val) {
|
||||
if (val == null) {
|
||||
elem[0].value = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (attr['ngFileSelect'] != '') {
|
||||
scope.change = scope.select;
|
||||
}
|
||||
elem.bind('change', function(evt) {
|
||||
var files = [], fileList, i;
|
||||
fileList = evt.__files_ || evt.target.files;
|
||||
updateModel(fileList, attr, ngModel, scope, evt);
|
||||
});
|
||||
|
||||
function updateModel(fileList, attr, ngModel, scope, evt) {
|
||||
$timeout(function() {
|
||||
var files = [];
|
||||
for (var i = 0; i < fileList.length; i++) {
|
||||
files.push(fileList.item(i));
|
||||
}
|
||||
if (ngModel) {
|
||||
scope.fileModel = files;
|
||||
ngModel && ngModel.$setViewValue(files != null && files.length == 0 ? '' : files);
|
||||
}
|
||||
$timeout(function() {
|
||||
scope.change({
|
||||
$files : files,
|
||||
$event : evt
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
angularFileUpload.directive('ngFileDrop', [ '$parse', '$timeout', '$location', function($parse, $timeout, $location) { return {
|
||||
restrict: 'AEC',
|
||||
require:'?ngModel',
|
||||
scope: {
|
||||
fileModel: '=ngModel',
|
||||
fileRejectedModel: '=ngFileRejectedModel',
|
||||
change: '&ngFileChange',
|
||||
drop: '&ngFileDrop',
|
||||
allowDir: '&allowDir',
|
||||
dragOverClass: '&dragOverClass',
|
||||
dropAvailable: '=dropAvailable',
|
||||
stopPropagation: '&stopPropagation',
|
||||
hideOnDropNotAvailable: '&hideOnDropNotAvailable',
|
||||
multiple: '&ngMultiple',
|
||||
accept: '&ngAccept'
|
||||
},
|
||||
link: function(scope, elem, attr, ngModel) {
|
||||
handleDrop(scope, elem, attr, ngModel, $parse, $timeout, $location);
|
||||
}
|
||||
}}]);
|
||||
|
||||
angularFileUpload.directive('ngNoFileDrop', function() {
|
||||
return function(scope, elem, attr) {
|
||||
if (dropAvailable()) elem.css('display', 'none')
|
||||
}
|
||||
});
|
||||
|
||||
//for backward compatibility
|
||||
angularFileUpload.directive('ngFileDropAvailable', [ '$parse', '$timeout', function($parse, $timeout) {
|
||||
return function(scope, elem, attr) {
|
||||
if (dropAvailable()) {
|
||||
var fn = $parse(attr['ngFileDropAvailable']);
|
||||
$timeout(function() {
|
||||
fn(scope);
|
||||
});
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
function handleDrop(scope, elem, attr, ngModel, $parse, $timeout, $location) {
|
||||
var available = dropAvailable();
|
||||
if (attr['dropAvailable']) {
|
||||
$timeout(function() {
|
||||
scope.dropAvailable = available;
|
||||
});
|
||||
}
|
||||
if (!available) {
|
||||
if (scope.hideOnDropNotAvailable() != false) {
|
||||
elem.css('display', 'none');
|
||||
}
|
||||
return;
|
||||
}
|
||||
var leaveTimeout = null;
|
||||
var stopPropagation = scope.stopPropagation();
|
||||
var dragOverDelay = 1;
|
||||
var accept = scope.accept() || attr['accept'] || attr['ngAccept'];
|
||||
var regexp = accept ? new RegExp(globStringToRegex(accept)) : null;
|
||||
elem[0].addEventListener('dragover', function(evt) {
|
||||
evt.preventDefault();
|
||||
if (stopPropagation) evt.stopPropagation();
|
||||
$timeout.cancel(leaveTimeout);
|
||||
if (!scope.actualDragOverClass) {
|
||||
scope.actualDragOverClass = calculateDragOverClass(scope, attr, evt);
|
||||
}
|
||||
elem.addClass(scope.actualDragOverClass);
|
||||
}, false);
|
||||
elem[0].addEventListener('dragenter', function(evt) {
|
||||
evt.preventDefault();
|
||||
if (stopPropagation) evt.stopPropagation();
|
||||
}, false);
|
||||
elem[0].addEventListener('dragleave', function(evt) {
|
||||
leaveTimeout = $timeout(function() {
|
||||
elem.removeClass(scope.actualDragOverClass);
|
||||
scope.actualDragOverClass = null;
|
||||
}, dragOverDelay || 1);
|
||||
}, false);
|
||||
if (attr['ngFileDrop'] != '') {
|
||||
scope.change = scope.drop;
|
||||
}
|
||||
elem[0].addEventListener('drop', function(evt) {
|
||||
evt.preventDefault();
|
||||
if (stopPropagation) evt.stopPropagation();
|
||||
elem.removeClass(scope.actualDragOverClass);
|
||||
scope.actualDragOverClass = null;
|
||||
extractFiles(evt, function(files, rejFiles) {
|
||||
if (ngModel) {
|
||||
scope.fileModel = files;
|
||||
ngModel && ngModel.$setViewValue(files != null && files.length == 0 ? '' : files);
|
||||
}
|
||||
if (attr['ngFileRejectedModel']) scope.fileRejectedModel = rejFiles;
|
||||
$timeout(function(){
|
||||
scope.change({
|
||||
$files : files,
|
||||
$rejectedFiles: rejFiles,
|
||||
$event : evt
|
||||
});
|
||||
});
|
||||
}, scope.allowDir() != false, attr['multiple'] || scope.multiple() || attr['ngMultiple'] == 'true');
|
||||
}, false);
|
||||
|
||||
function calculateDragOverClass(scope, attr, evt) {
|
||||
var valid = true;
|
||||
if (regexp) {
|
||||
var items = evt.dataTransfer.items;
|
||||
if (items != null) {
|
||||
for (var i = 0 ; i < items.length && valid; i++) {
|
||||
valid = valid && (items[i].kind == 'file' || items[i].kind == '') &&
|
||||
(items[i].type.match(regexp) != null || (items[i].name != null && items[i].name.match(regexp) != null));
|
||||
}
|
||||
}
|
||||
}
|
||||
var clazz = scope.dragOverClass({$event : evt});
|
||||
if (clazz) {
|
||||
if (clazz.delay) dragOverDelay = clazz.delay;
|
||||
if (clazz.accept) clazz = valid ? clazz.accept : clazz.reject;
|
||||
}
|
||||
return clazz || attr['dragOverClass'] || 'dragover';
|
||||
}
|
||||
|
||||
function extractFiles(evt, callback, allowDir, multiple) {
|
||||
var files = [], rejFiles = [], items = evt.dataTransfer.items;
|
||||
|
||||
function addFile(file) {
|
||||
if (!regexp || file.type.match(regexp) || (file.name != null && file.name.match(regexp))) {
|
||||
files.push(file);
|
||||
} else {
|
||||
rejFiles.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
if (items && items.length > 0 && $location.protocol() != 'file') {
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i].webkitGetAsEntry && items[i].webkitGetAsEntry() && items[i].webkitGetAsEntry().isDirectory) {
|
||||
var entry = items[i].webkitGetAsEntry();
|
||||
if (entry.isDirectory && !allowDir) {
|
||||
continue;
|
||||
}
|
||||
if (entry != null) {
|
||||
//fix for chrome bug https://code.google.com/p/chromium/issues/detail?id=149735
|
||||
if (isASCII(entry.name)) {
|
||||
traverseFileTree(files, entry);
|
||||
} else if (!items[i].webkitGetAsEntry().isDirectory) {
|
||||
addFile(items[i].getAsFile());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var f = items[i].getAsFile();
|
||||
if (f != null) addFile(f);
|
||||
}
|
||||
if (!multiple && files.length > 0) break;
|
||||
}
|
||||
} else {
|
||||
var fileList = evt.dataTransfer.files;
|
||||
if (fileList != null) {
|
||||
for (var i = 0; i < fileList.length; i++) {
|
||||
addFile(fileList.item(i));
|
||||
if (!multiple && files.length > 0) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
var delays = 0;
|
||||
(function waitForProcess(delay) {
|
||||
$timeout(function() {
|
||||
if (!processing) {
|
||||
if (!multiple && files.length > 1) {
|
||||
var i = 0;
|
||||
while (files[i].type == 'directory') i++;
|
||||
files = [files[i]];
|
||||
}
|
||||
callback(files, rejFiles);
|
||||
} else {
|
||||
if (delays++ * 10 < 20 * 1000) {
|
||||
waitForProcess(10);
|
||||
}
|
||||
}
|
||||
}, delay || 0)
|
||||
})();
|
||||
|
||||
var processing = 0;
|
||||
function traverseFileTree(files, entry, path) {
|
||||
if (entry != null) {
|
||||
if (entry.isDirectory) {
|
||||
addFile({name: entry.name, type: 'directory', path: (path ? path : '') + entry.name});
|
||||
var dirReader = entry.createReader();
|
||||
processing++;
|
||||
dirReader.readEntries(function(entries) {
|
||||
try {
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
traverseFileTree(files, entries[i], (path ? path : '') + entry.name + '/');
|
||||
}
|
||||
} finally {
|
||||
processing--;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
processing++;
|
||||
entry.file(function(file) {
|
||||
processing--;
|
||||
file.path = (path ? path : '') + file.name;
|
||||
addFile(file);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function dropAvailable() {
|
||||
var div = document.createElement('div');
|
||||
return ('draggable' in div) && ('ondrop' in div);
|
||||
}
|
||||
|
||||
function isASCII(str) {
|
||||
return /^[\000-\177]*$/.test(str);
|
||||
}
|
||||
|
||||
function globStringToRegex(str) {
|
||||
if (str.length > 2 && str[0] === '/' && str[str.length -1] === '/') {
|
||||
return str.substring(1, str.length - 1);
|
||||
}
|
||||
var split = str.split(','), result = '';
|
||||
if (split.length > 1) {
|
||||
for (var i = 0; i < split.length; i++) {
|
||||
result += '(' + globStringToRegex(split[i]) + ')';
|
||||
if (i < split.length - 1) {
|
||||
result += '|'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = '^' + str.replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\' + '-]', 'g'), '\\$&') + '$';
|
||||
result = result.replace(/\\\*/g, '.*').replace(/\\\?/g, '.');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
})();
|
245
src/main/webapp/js/lib/angular-mocks.js
vendored
245
src/main/webapp/js/lib/angular-mocks.js
vendored
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* @license AngularJS v1.3.0
|
||||
* @license AngularJS v1.3.11
|
||||
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
|
@ -74,7 +74,7 @@ angular.mock.$Browser = function() {
|
|||
self.defer = function(fn, delay) {
|
||||
delay = delay || 0;
|
||||
self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId});
|
||||
self.deferredFns.sort(function(a,b){ return a.time - b.time;});
|
||||
self.deferredFns.sort(function(a, b) { return a.time - b.time;});
|
||||
return self.deferredNextId++;
|
||||
};
|
||||
|
||||
|
@ -117,7 +117,7 @@ angular.mock.$Browser = function() {
|
|||
self.defer.now += delay;
|
||||
} else {
|
||||
if (self.deferredFns.length) {
|
||||
self.defer.now = self.deferredFns[self.deferredFns.length-1].time;
|
||||
self.defer.now = self.deferredFns[self.deferredFns.length - 1].time;
|
||||
} else {
|
||||
throw new Error('No deferred tasks to be flushed');
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ angular.mock.$Browser.prototype = {
|
|||
* run all fns in pollFns
|
||||
*/
|
||||
poll: function poll() {
|
||||
angular.forEach(this.pollFns, function(pollFn){
|
||||
angular.forEach(this.pollFns, function(pollFn) {
|
||||
pollFn();
|
||||
});
|
||||
},
|
||||
|
@ -250,31 +250,31 @@ angular.mock.$ExceptionHandlerProvider = function() {
|
|||
*
|
||||
* @param {string} mode Mode of operation, defaults to `rethrow`.
|
||||
*
|
||||
* - `rethrow`: If any errors are passed to the handler in tests, it typically means that there
|
||||
* is a bug in the application or test, so this mock will make these tests fail.
|
||||
* - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log`
|
||||
* mode stores an array of errors in `$exceptionHandler.errors`, to allow later
|
||||
* assertion of them. See {@link ngMock.$log#assertEmpty assertEmpty()} and
|
||||
* {@link ngMock.$log#reset reset()}
|
||||
* - `rethrow`: If any errors are passed to the handler in tests, it typically means that there
|
||||
* is a bug in the application or test, so this mock will make these tests fail.
|
||||
* For any implementations that expect exceptions to be thrown, the `rethrow` mode
|
||||
* will also maintain a log of thrown errors.
|
||||
*/
|
||||
this.mode = function(mode) {
|
||||
switch(mode) {
|
||||
case 'rethrow':
|
||||
handler = function(e) {
|
||||
throw e;
|
||||
};
|
||||
break;
|
||||
case 'log':
|
||||
var errors = [];
|
||||
|
||||
switch (mode) {
|
||||
case 'log':
|
||||
case 'rethrow':
|
||||
var errors = [];
|
||||
handler = function(e) {
|
||||
if (arguments.length == 1) {
|
||||
errors.push(e);
|
||||
} else {
|
||||
errors.push([].slice.call(arguments, 0));
|
||||
}
|
||||
if (mode === "rethrow") {
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
handler.errors = errors;
|
||||
break;
|
||||
default:
|
||||
|
@ -316,7 +316,7 @@ angular.mock.$LogProvider = function() {
|
|||
}
|
||||
};
|
||||
|
||||
this.$get = function () {
|
||||
this.$get = function() {
|
||||
var $log = {
|
||||
log: function() { $log.log.logs.push(concat([], arguments, 0)); },
|
||||
warn: function() { $log.warn.logs.push(concat([], arguments, 0)); },
|
||||
|
@ -336,7 +336,7 @@ angular.mock.$LogProvider = function() {
|
|||
* @description
|
||||
* Reset all of the logging arrays to empty.
|
||||
*/
|
||||
$log.reset = function () {
|
||||
$log.reset = function() {
|
||||
/**
|
||||
* @ngdoc property
|
||||
* @name $log#log.logs
|
||||
|
@ -421,14 +421,14 @@ angular.mock.$LogProvider = function() {
|
|||
var errors = [];
|
||||
angular.forEach(['error', 'warn', 'info', 'log', 'debug'], function(logLevel) {
|
||||
angular.forEach($log[logLevel].logs, function(log) {
|
||||
angular.forEach(log, function (logItem) {
|
||||
angular.forEach(log, function(logItem) {
|
||||
errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' +
|
||||
(logItem.stack || ''));
|
||||
});
|
||||
});
|
||||
});
|
||||
if (errors.length) {
|
||||
errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or "+
|
||||
errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or " +
|
||||
"an expected log message was not checked and removed:");
|
||||
errors.push('');
|
||||
throw new Error(errors.join('\n---------\n'));
|
||||
|
@ -461,17 +461,17 @@ angular.mock.$LogProvider = function() {
|
|||
* @returns {promise} A promise which will be notified on each iteration.
|
||||
*/
|
||||
angular.mock.$IntervalProvider = function() {
|
||||
this.$get = ['$rootScope', '$q',
|
||||
function($rootScope, $q) {
|
||||
this.$get = ['$browser', '$rootScope', '$q', '$$q',
|
||||
function($browser, $rootScope, $q, $$q) {
|
||||
var repeatFns = [],
|
||||
nextRepeatId = 0,
|
||||
now = 0;
|
||||
|
||||
var $interval = function(fn, delay, count, invokeApply) {
|
||||
var deferred = $q.defer(),
|
||||
promise = deferred.promise,
|
||||
iteration = 0,
|
||||
skipApply = (angular.isDefined(invokeApply) && !invokeApply);
|
||||
var iteration = 0,
|
||||
skipApply = (angular.isDefined(invokeApply) && !invokeApply),
|
||||
deferred = (skipApply ? $$q : $q).defer(),
|
||||
promise = deferred.promise;
|
||||
|
||||
count = (angular.isDefined(count)) ? count : 0;
|
||||
promise.then(null, null, fn);
|
||||
|
@ -494,7 +494,11 @@ angular.mock.$IntervalProvider = function() {
|
|||
}
|
||||
}
|
||||
|
||||
if (!skipApply) $rootScope.$apply();
|
||||
if (skipApply) {
|
||||
$browser.defer.flush();
|
||||
} else {
|
||||
$rootScope.$apply();
|
||||
}
|
||||
}
|
||||
|
||||
repeatFns.push({
|
||||
|
@ -504,7 +508,7 @@ angular.mock.$IntervalProvider = function() {
|
|||
id: nextRepeatId,
|
||||
deferred: deferred
|
||||
});
|
||||
repeatFns.sort(function(a,b){ return a.nextTime - b.nextTime;});
|
||||
repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;});
|
||||
|
||||
nextRepeatId++;
|
||||
return promise;
|
||||
|
@ -520,7 +524,7 @@ angular.mock.$IntervalProvider = function() {
|
|||
* @returns {boolean} Returns `true` if the task was successfully cancelled.
|
||||
*/
|
||||
$interval.cancel = function(promise) {
|
||||
if(!promise) return false;
|
||||
if (!promise) return false;
|
||||
var fnIndex;
|
||||
|
||||
angular.forEach(repeatFns, function(fn, index) {
|
||||
|
@ -553,7 +557,7 @@ angular.mock.$IntervalProvider = function() {
|
|||
var task = repeatFns[0];
|
||||
task.fn();
|
||||
task.nextTime += task.delay;
|
||||
repeatFns.sort(function(a,b){ return a.nextTime - b.nextTime;});
|
||||
repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;});
|
||||
}
|
||||
return millis;
|
||||
};
|
||||
|
@ -581,10 +585,10 @@ function jsonStringToDate(string) {
|
|||
tzMin = int(match[9] + match[11]);
|
||||
}
|
||||
date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
|
||||
date.setUTCHours(int(match[4]||0) - tzHour,
|
||||
int(match[5]||0) - tzMin,
|
||||
int(match[6]||0),
|
||||
int(match[7]||0));
|
||||
date.setUTCHours(int(match[4] || 0) - tzHour,
|
||||
int(match[5] || 0) - tzMin,
|
||||
int(match[6] || 0),
|
||||
int(match[7] || 0));
|
||||
return date;
|
||||
}
|
||||
return string;
|
||||
|
@ -601,7 +605,7 @@ function padNumber(num, digits, trim) {
|
|||
num = -num;
|
||||
}
|
||||
num = '' + num;
|
||||
while(num.length < digits) num = '0' + num;
|
||||
while (num.length < digits) num = '0' + num;
|
||||
if (trim)
|
||||
num = num.substr(num.length - digits);
|
||||
return neg + num;
|
||||
|
@ -645,7 +649,7 @@ function padNumber(num, digits, trim) {
|
|||
* ```
|
||||
*
|
||||
*/
|
||||
angular.mock.TzDate = function (offset, timestamp) {
|
||||
angular.mock.TzDate = function(offset, timestamp) {
|
||||
var self = new Date(0);
|
||||
if (angular.isString(timestamp)) {
|
||||
var tsStr = timestamp;
|
||||
|
@ -663,7 +667,7 @@ angular.mock.TzDate = function (offset, timestamp) {
|
|||
}
|
||||
|
||||
var localOffset = new Date(timestamp).getTimezoneOffset();
|
||||
self.offsetDiff = localOffset*60*1000 - offset*1000*60*60;
|
||||
self.offsetDiff = localOffset * 60 * 1000 - offset * 1000 * 60 * 60;
|
||||
self.date = new Date(timestamp + self.offsetDiff);
|
||||
|
||||
self.getTime = function() {
|
||||
|
@ -788,20 +792,20 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
|
|||
$provide.decorator('$animate', ['$delegate', '$$asyncCallback', '$timeout', '$browser',
|
||||
function($delegate, $$asyncCallback, $timeout, $browser) {
|
||||
var animate = {
|
||||
queue : [],
|
||||
cancel : $delegate.cancel,
|
||||
enabled : $delegate.enabled,
|
||||
triggerCallbackEvents : function() {
|
||||
queue: [],
|
||||
cancel: $delegate.cancel,
|
||||
enabled: $delegate.enabled,
|
||||
triggerCallbackEvents: function() {
|
||||
$$asyncCallback.flush();
|
||||
},
|
||||
triggerCallbackPromise : function() {
|
||||
triggerCallbackPromise: function() {
|
||||
$timeout.flush(0);
|
||||
},
|
||||
triggerCallbacks : function() {
|
||||
triggerCallbacks: function() {
|
||||
this.triggerCallbackEvents();
|
||||
this.triggerCallbackPromise();
|
||||
},
|
||||
triggerReflow : function() {
|
||||
triggerReflow: function() {
|
||||
angular.forEach(reflowQueue, function(fn) {
|
||||
fn();
|
||||
});
|
||||
|
@ -813,10 +817,10 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
|
|||
['animate','enter','leave','move','addClass','removeClass','setClass'], function(method) {
|
||||
animate[method] = function() {
|
||||
animate.queue.push({
|
||||
event : method,
|
||||
element : arguments[0],
|
||||
options : arguments[arguments.length-1],
|
||||
args : arguments
|
||||
event: method,
|
||||
element: arguments[0],
|
||||
options: arguments[arguments.length - 1],
|
||||
args: arguments
|
||||
});
|
||||
return $delegate[method].apply($delegate, arguments);
|
||||
};
|
||||
|
@ -883,13 +887,13 @@ angular.mock.dump = function(object) {
|
|||
function serializeScope(scope, offset) {
|
||||
offset = offset || ' ';
|
||||
var log = [offset + 'Scope(' + scope.$id + '): {'];
|
||||
for ( var key in scope ) {
|
||||
for (var key in scope) {
|
||||
if (Object.prototype.hasOwnProperty.call(scope, key) && !key.match(/^(\$|this)/)) {
|
||||
log.push(' ' + key + ': ' + angular.toJson(scope[key]));
|
||||
}
|
||||
}
|
||||
var child = scope.$$childHead;
|
||||
while(child) {
|
||||
while (child) {
|
||||
log.push(serializeScope(child, offset + ' '));
|
||||
child = child.$$nextSibling;
|
||||
}
|
||||
|
@ -1115,7 +1119,7 @@ angular.mock.dump = function(object) {
|
|||
```
|
||||
*/
|
||||
angular.mock.$HttpBackendProvider = function() {
|
||||
this.$get = ['$rootScope', createHttpBackendMock];
|
||||
this.$get = ['$rootScope', '$timeout', createHttpBackendMock];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1132,7 +1136,7 @@ angular.mock.$HttpBackendProvider = function() {
|
|||
* @param {Object=} $browser Auto-flushing enabled if specified
|
||||
* @return {Object} Instance of $httpBackend mock
|
||||
*/
|
||||
function createHttpBackendMock($rootScope, $delegate, $browser) {
|
||||
function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
|
||||
var definitions = [],
|
||||
expectations = [],
|
||||
responses = [],
|
||||
|
@ -1145,7 +1149,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
return function() {
|
||||
return angular.isNumber(status)
|
||||
? [status, data, headers, statusText]
|
||||
: [200, status, data];
|
||||
: [200, status, data, headers];
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1162,7 +1166,9 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
}
|
||||
|
||||
function wrapResponse(wrapped) {
|
||||
if (!$browser && timeout && timeout.then) timeout.then(handleTimeout);
|
||||
if (!$browser && timeout) {
|
||||
timeout.then ? timeout.then(handleTimeout) : $timeout(handleTimeout, timeout);
|
||||
}
|
||||
|
||||
return handleResponse;
|
||||
|
||||
|
@ -1277,7 +1283,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
* order to change how a matched request is handled.
|
||||
*/
|
||||
|
@ -1291,7 +1297,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
* order to change how a matched request is handled.
|
||||
*/
|
||||
|
@ -1305,7 +1311,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
* order to change how a matched request is handled.
|
||||
*/
|
||||
|
@ -1321,7 +1327,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
* @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
|
||||
* data string and returns true if the data is as expected.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
* order to change how a matched request is handled.
|
||||
*/
|
||||
|
@ -1337,7 +1343,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
* @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
|
||||
* data string and returns true if the data is as expected.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
* order to change how a matched request is handled.
|
||||
*/
|
||||
|
@ -1350,7 +1356,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
* order to change how a matched request is handled.
|
||||
*/
|
||||
|
@ -1371,7 +1377,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
* is in JSON format.
|
||||
* @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
|
||||
* object and returns true if the headers match the current expectation.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
* order to change how a matched request is handled.
|
||||
*
|
||||
|
@ -1386,7 +1392,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
$httpBackend.expect = function(method, url, data, headers) {
|
||||
var expectation = new MockHttpExpectation(method, url, data, headers),
|
||||
chain = {
|
||||
respond: function (status, data, headers, statusText) {
|
||||
respond: function(status, data, headers, statusText) {
|
||||
expectation.response = createResponse(status, data, headers, statusText);
|
||||
return chain;
|
||||
}
|
||||
|
@ -1406,7 +1412,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {Object=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
* order to change how a matched request is handled. See #expect for more info.
|
||||
*/
|
||||
|
@ -1420,7 +1426,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {Object=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
* order to change how a matched request is handled.
|
||||
*/
|
||||
|
@ -1434,7 +1440,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @param {Object=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
* order to change how a matched request is handled.
|
||||
*/
|
||||
|
@ -1451,7 +1457,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
* receives data string and returns true if the data is as expected, or Object if request body
|
||||
* is in JSON format.
|
||||
* @param {Object=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
* order to change how a matched request is handled.
|
||||
*/
|
||||
|
@ -1468,7 +1474,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
* receives data string and returns true if the data is as expected, or Object if request body
|
||||
* is in JSON format.
|
||||
* @param {Object=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
* order to change how a matched request is handled.
|
||||
*/
|
||||
|
@ -1485,7 +1491,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
* receives data string and returns true if the data is as expected, or Object if request body
|
||||
* is in JSON format.
|
||||
* @param {Object=} headers HTTP headers.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
* order to change how a matched request is handled.
|
||||
*/
|
||||
|
@ -1498,7 +1504,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
|||
*
|
||||
* @param {string|RegExp|function(string)} url HTTP url or function that receives the url
|
||||
* and returns true if the url match the current definition.
|
||||
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
|
||||
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
|
||||
* request is handled. You can save this object for later use and invoke `respond` again in
|
||||
* order to change how a matched request is handled.
|
||||
*/
|
||||
|
@ -1636,7 +1642,9 @@ function MockHttpExpectation(method, url, data, headers) {
|
|||
if (angular.isUndefined(data)) return true;
|
||||
if (data && angular.isFunction(data.test)) return data.test(d);
|
||||
if (data && angular.isFunction(data)) return data(d);
|
||||
if (data && !angular.isString(data)) return angular.equals(data, angular.fromJson(d));
|
||||
if (data && !angular.isString(data)) {
|
||||
return angular.equals(angular.fromJson(angular.toJson(data)), angular.fromJson(d));
|
||||
}
|
||||
return data == d;
|
||||
};
|
||||
|
||||
|
@ -1709,7 +1717,7 @@ function MockXhr() {
|
|||
* that adds a "flush" and "verifyNoPendingTasks" methods.
|
||||
*/
|
||||
|
||||
angular.mock.$TimeoutDecorator = ['$delegate', '$browser', function ($delegate, $browser) {
|
||||
angular.mock.$TimeoutDecorator = ['$delegate', '$browser', function($delegate, $browser) {
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
|
@ -1763,12 +1771,12 @@ angular.mock.$RAFDecorator = ['$delegate', function($delegate) {
|
|||
rafFn.supported = $delegate.supported;
|
||||
|
||||
rafFn.flush = function() {
|
||||
if(queue.length === 0) {
|
||||
if (queue.length === 0) {
|
||||
throw new Error('No rAF callbacks present');
|
||||
}
|
||||
|
||||
var length = queue.length;
|
||||
for(var i=0;i<length;i++) {
|
||||
for (var i = 0; i < length; i++) {
|
||||
queue[i]();
|
||||
}
|
||||
|
||||
|
@ -1828,6 +1836,7 @@ angular.module('ngMock', ['ng']).provider({
|
|||
$provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
|
||||
$provide.decorator('$$rAF', angular.mock.$RAFDecorator);
|
||||
$provide.decorator('$$asyncCallback', angular.mock.$AsyncCallbackDecorator);
|
||||
$provide.decorator('$rootScope', angular.mock.$RootScopeDecorator);
|
||||
}]);
|
||||
|
||||
/**
|
||||
|
@ -2033,10 +2042,96 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
|
|||
*/
|
||||
angular.mock.e2e = {};
|
||||
angular.mock.e2e.$httpBackendDecorator =
|
||||
['$rootScope', '$delegate', '$browser', createHttpBackendMock];
|
||||
['$rootScope', '$timeout', '$delegate', '$browser', createHttpBackendMock];
|
||||
|
||||
|
||||
if(window.jasmine || window.mocha) {
|
||||
/**
|
||||
* @ngdoc type
|
||||
* @name $rootScope.Scope
|
||||
* @module ngMock
|
||||
* @description
|
||||
* {@link ng.$rootScope.Scope Scope} type decorated with helper methods useful for testing. These
|
||||
* methods are automatically available on any {@link ng.$rootScope.Scope Scope} instance when
|
||||
* `ngMock` module is loaded.
|
||||
*
|
||||
* In addition to all the regular `Scope` methods, the following helper methods are available:
|
||||
*/
|
||||
angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
|
||||
|
||||
var $rootScopePrototype = Object.getPrototypeOf($delegate);
|
||||
|
||||
$rootScopePrototype.$countChildScopes = countChildScopes;
|
||||
$rootScopePrototype.$countWatchers = countWatchers;
|
||||
|
||||
return $delegate;
|
||||
|
||||
// ------------------------------------------------------------------------------------------ //
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $rootScope.Scope#$countChildScopes
|
||||
* @module ngMock
|
||||
* @description
|
||||
* Counts all the direct and indirect child scopes of the current scope.
|
||||
*
|
||||
* The current scope is excluded from the count. The count includes all isolate child scopes.
|
||||
*
|
||||
* @returns {number} Total number of child scopes.
|
||||
*/
|
||||
function countChildScopes() {
|
||||
// jshint validthis: true
|
||||
var count = 0; // exclude the current scope
|
||||
var pendingChildHeads = [this.$$childHead];
|
||||
var currentScope;
|
||||
|
||||
while (pendingChildHeads.length) {
|
||||
currentScope = pendingChildHeads.shift();
|
||||
|
||||
while (currentScope) {
|
||||
count += 1;
|
||||
pendingChildHeads.push(currentScope.$$childHead);
|
||||
currentScope = currentScope.$$nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $rootScope.Scope#$countWatchers
|
||||
* @module ngMock
|
||||
* @description
|
||||
* Counts all the watchers of direct and indirect child scopes of the current scope.
|
||||
*
|
||||
* The watchers of the current scope are included in the count and so are all the watchers of
|
||||
* isolate child scopes.
|
||||
*
|
||||
* @returns {number} Total number of watchers.
|
||||
*/
|
||||
function countWatchers() {
|
||||
// jshint validthis: true
|
||||
var count = this.$$watchers ? this.$$watchers.length : 0; // include the current scope
|
||||
var pendingChildHeads = [this.$$childHead];
|
||||
var currentScope;
|
||||
|
||||
while (pendingChildHeads.length) {
|
||||
currentScope = pendingChildHeads.shift();
|
||||
|
||||
while (currentScope) {
|
||||
count += currentScope.$$watchers ? currentScope.$$watchers.length : 0;
|
||||
pendingChildHeads.push(currentScope.$$childHead);
|
||||
currentScope = currentScope.$$nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}];
|
||||
|
||||
|
||||
if (window.jasmine || window.mocha) {
|
||||
|
||||
var currentSpec = null,
|
||||
isSpecRunning = function() {
|
||||
|
@ -2244,7 +2339,7 @@ if(window.jasmine || window.mocha) {
|
|||
injector = currentSpec.$injector = angular.injector(modules, strictDi);
|
||||
currentSpec.$injectorStrict = strictDi;
|
||||
}
|
||||
for(var i = 0, ii = blockFns.length; i < ii; i++) {
|
||||
for (var i = 0, ii = blockFns.length; i < ii; i++) {
|
||||
if (currentSpec.$injectorStrict) {
|
||||
// If the injector is strict / strictDi, and the spec wants to inject using automatic
|
||||
// annotation, then annotate the function here.
|
||||
|
|
667
src/main/webapp/js/lib/angular-resource.js
vendored
Normal file
667
src/main/webapp/js/lib/angular-resource.js
vendored
Normal file
|
@ -0,0 +1,667 @@
|
|||
/**
|
||||
* @license AngularJS v1.3.11
|
||||
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {'use strict';
|
||||
|
||||
var $resourceMinErr = angular.$$minErr('$resource');
|
||||
|
||||
// Helper functions and regex to lookup a dotted path on an object
|
||||
// stopping at undefined/null. The path must be composed of ASCII
|
||||
// identifiers (just like $parse)
|
||||
var MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;
|
||||
|
||||
function isValidDottedPath(path) {
|
||||
return (path != null && path !== '' && path !== 'hasOwnProperty' &&
|
||||
MEMBER_NAME_REGEX.test('.' + path));
|
||||
}
|
||||
|
||||
function lookupDottedPath(obj, path) {
|
||||
if (!isValidDottedPath(path)) {
|
||||
throw $resourceMinErr('badmember', 'Dotted member path "@{0}" is invalid.', path);
|
||||
}
|
||||
var keys = path.split('.');
|
||||
for (var i = 0, ii = keys.length; i < ii && obj !== undefined; i++) {
|
||||
var key = keys[i];
|
||||
obj = (obj !== null) ? obj[key] : undefined;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a shallow copy of an object and clear other fields from the destination
|
||||
*/
|
||||
function shallowClearAndCopy(src, dst) {
|
||||
dst = dst || {};
|
||||
|
||||
angular.forEach(dst, function(value, key) {
|
||||
delete dst[key];
|
||||
});
|
||||
|
||||
for (var key in src) {
|
||||
if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
|
||||
dst[key] = src[key];
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name ngResource
|
||||
* @description
|
||||
*
|
||||
* # ngResource
|
||||
*
|
||||
* The `ngResource` module provides interaction support with RESTful services
|
||||
* via the $resource service.
|
||||
*
|
||||
*
|
||||
* <div doc-module-components="ngResource"></div>
|
||||
*
|
||||
* See {@link ngResource.$resource `$resource`} for usage.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name $resource
|
||||
* @requires $http
|
||||
*
|
||||
* @description
|
||||
* A factory which creates a resource object that lets you interact with
|
||||
* [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources.
|
||||
*
|
||||
* The returned resource object has action methods which provide high-level behaviors without
|
||||
* the need to interact with the low level {@link ng.$http $http} service.
|
||||
*
|
||||
* Requires the {@link ngResource `ngResource`} module to be installed.
|
||||
*
|
||||
* By default, trailing slashes will be stripped from the calculated URLs,
|
||||
* which can pose problems with server backends that do not expect that
|
||||
* behavior. This can be disabled by configuring the `$resourceProvider` like
|
||||
* this:
|
||||
*
|
||||
* ```js
|
||||
app.config(['$resourceProvider', function($resourceProvider) {
|
||||
// Don't strip trailing slashes from calculated URLs
|
||||
$resourceProvider.defaults.stripTrailingSlashes = false;
|
||||
}]);
|
||||
* ```
|
||||
*
|
||||
* @param {string} url A parametrized URL template with parameters prefixed by `:` as in
|
||||
* `/user/:username`. If you are using a URL with a port number (e.g.
|
||||
* `http://example.com:8080/api`), it will be respected.
|
||||
*
|
||||
* If you are using a url with a suffix, just add the suffix, like this:
|
||||
* `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')`
|
||||
* or even `$resource('http://example.com/resource/:resource_id.:format')`
|
||||
* If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be
|
||||
* collapsed down to a single `.`. If you need this sequence to appear and not collapse then you
|
||||
* can escape it with `/\.`.
|
||||
*
|
||||
* @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
|
||||
* `actions` methods. If any of the parameter value is a function, it will be executed every time
|
||||
* when a param value needs to be obtained for a request (unless the param was overridden).
|
||||
*
|
||||
* Each key value in the parameter object is first bound to url template if present and then any
|
||||
* excess keys are appended to the url search query after the `?`.
|
||||
*
|
||||
* Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
|
||||
* URL `/path/greet?salutation=Hello`.
|
||||
*
|
||||
* If the parameter value is prefixed with `@` then the value for that parameter will be extracted
|
||||
* from the corresponding property on the `data` object (provided when calling an action method). For
|
||||
* example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of `someParam`
|
||||
* will be `data.someProp`.
|
||||
*
|
||||
* @param {Object.<Object>=} actions Hash with declaration of custom actions that should extend
|
||||
* the default set of resource actions. The declaration should be created in the format of {@link
|
||||
* ng.$http#usage $http.config}:
|
||||
*
|
||||
* {action1: {method:?, params:?, isArray:?, headers:?, ...},
|
||||
* action2: {method:?, params:?, isArray:?, headers:?, ...},
|
||||
* ...}
|
||||
*
|
||||
* Where:
|
||||
*
|
||||
* - **`action`** – {string} – The name of action. This name becomes the name of the method on
|
||||
* your resource object.
|
||||
* - **`method`** – {string} – Case insensitive HTTP method (e.g. `GET`, `POST`, `PUT`,
|
||||
* `DELETE`, `JSONP`, etc).
|
||||
* - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of
|
||||
* the parameter value is a function, it will be executed every time when a param value needs to
|
||||
* be obtained for a request (unless the param was overridden).
|
||||
* - **`url`** – {string} – action specific `url` override. The url templating is supported just
|
||||
* like for the resource-level urls.
|
||||
* - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
|
||||
* see `returns` section.
|
||||
* - **`transformRequest`** –
|
||||
* `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
|
||||
* transform function or an array of such functions. The transform function takes the http
|
||||
* request body and headers and returns its transformed (typically serialized) version.
|
||||
* By default, transformRequest will contain one function that checks if the request data is
|
||||
* an object and serializes to using `angular.toJson`. To prevent this behavior, set
|
||||
* `transformRequest` to an empty array: `transformRequest: []`
|
||||
* - **`transformResponse`** –
|
||||
* `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
|
||||
* transform function or an array of such functions. The transform function takes the http
|
||||
* response body and headers and returns its transformed (typically deserialized) version.
|
||||
* By default, transformResponse will contain one function that checks if the response looks like
|
||||
* a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior, set
|
||||
* `transformResponse` to an empty array: `transformResponse: []`
|
||||
* - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
|
||||
* GET request, otherwise if a cache instance built with
|
||||
* {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
|
||||
* caching.
|
||||
* - **`timeout`** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} that
|
||||
* should abort the request when resolved.
|
||||
* - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
|
||||
* XHR object. See
|
||||
* [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5)
|
||||
* for more information.
|
||||
* - **`responseType`** - `{string}` - see
|
||||
* [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
|
||||
* - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
|
||||
* `response` and `responseError`. Both `response` and `responseError` interceptors get called
|
||||
* with `http response` object. See {@link ng.$http $http interceptors}.
|
||||
*
|
||||
* @param {Object} options Hash with custom settings that should extend the
|
||||
* default `$resourceProvider` behavior. The only supported option is
|
||||
*
|
||||
* Where:
|
||||
*
|
||||
* - **`stripTrailingSlashes`** – {boolean} – If true then the trailing
|
||||
* slashes from any calculated URL will be stripped. (Defaults to true.)
|
||||
*
|
||||
* @returns {Object} A resource "class" object with methods for the default set of resource actions
|
||||
* optionally extended with custom `actions`. The default set contains these actions:
|
||||
* ```js
|
||||
* { 'get': {method:'GET'},
|
||||
* 'save': {method:'POST'},
|
||||
* 'query': {method:'GET', isArray:true},
|
||||
* 'remove': {method:'DELETE'},
|
||||
* 'delete': {method:'DELETE'} };
|
||||
* ```
|
||||
*
|
||||
* Calling these methods invoke an {@link ng.$http} with the specified http method,
|
||||
* destination and parameters. When the data is returned from the server then the object is an
|
||||
* instance of the resource class. The actions `save`, `remove` and `delete` are available on it
|
||||
* as methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
|
||||
* read, update, delete) on server-side data like this:
|
||||
* ```js
|
||||
* var User = $resource('/user/:userId', {userId:'@id'});
|
||||
* var user = User.get({userId:123}, function() {
|
||||
* user.abc = true;
|
||||
* user.$save();
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* It is important to realize that invoking a $resource object method immediately returns an
|
||||
* empty reference (object or array depending on `isArray`). Once the data is returned from the
|
||||
* server the existing reference is populated with the actual data. This is a useful trick since
|
||||
* usually the resource is assigned to a model which is then rendered by the view. Having an empty
|
||||
* object results in no rendering, once the data arrives from the server then the object is
|
||||
* populated with the data and the view automatically re-renders itself showing the new data. This
|
||||
* means that in most cases one never has to write a callback function for the action methods.
|
||||
*
|
||||
* The action methods on the class object or instance object can be invoked with the following
|
||||
* parameters:
|
||||
*
|
||||
* - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])`
|
||||
* - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
|
||||
* - non-GET instance actions: `instance.$action([parameters], [success], [error])`
|
||||
*
|
||||
* Success callback is called with (value, responseHeaders) arguments. Error callback is called
|
||||
* with (httpResponse) argument.
|
||||
*
|
||||
* Class actions return empty instance (with additional properties below).
|
||||
* Instance actions return promise of the action.
|
||||
*
|
||||
* The Resource instances and collection have these additional properties:
|
||||
*
|
||||
* - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
|
||||
* instance or collection.
|
||||
*
|
||||
* On success, the promise is resolved with the same resource instance or collection object,
|
||||
* updated with data from server. This makes it easy to use in
|
||||
* {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view
|
||||
* rendering until the resource(s) are loaded.
|
||||
*
|
||||
* On failure, the promise is resolved with the {@link ng.$http http response} object, without
|
||||
* the `resource` property.
|
||||
*
|
||||
* If an interceptor object was provided, the promise will instead be resolved with the value
|
||||
* returned by the interceptor.
|
||||
*
|
||||
* - `$resolved`: `true` after first server interaction is completed (either with success or
|
||||
* rejection), `false` before that. Knowing if the Resource has been resolved is useful in
|
||||
* data-binding.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* # Credit card resource
|
||||
*
|
||||
* ```js
|
||||
// Define CreditCard class
|
||||
var CreditCard = $resource('/user/:userId/card/:cardId',
|
||||
{userId:123, cardId:'@id'}, {
|
||||
charge: {method:'POST', params:{charge:true}}
|
||||
});
|
||||
|
||||
// We can retrieve a collection from the server
|
||||
var cards = CreditCard.query(function() {
|
||||
// GET: /user/123/card
|
||||
// server returns: [ {id:456, number:'1234', name:'Smith'} ];
|
||||
|
||||
var card = cards[0];
|
||||
// each item is an instance of CreditCard
|
||||
expect(card instanceof CreditCard).toEqual(true);
|
||||
card.name = "J. Smith";
|
||||
// non GET methods are mapped onto the instances
|
||||
card.$save();
|
||||
// POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
|
||||
// server returns: {id:456, number:'1234', name: 'J. Smith'};
|
||||
|
||||
// our custom method is mapped as well.
|
||||
card.$charge({amount:9.99});
|
||||
// POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
|
||||
});
|
||||
|
||||
// we can create an instance as well
|
||||
var newCard = new CreditCard({number:'0123'});
|
||||
newCard.name = "Mike Smith";
|
||||
newCard.$save();
|
||||
// POST: /user/123/card {number:'0123', name:'Mike Smith'}
|
||||
// server returns: {id:789, number:'0123', name: 'Mike Smith'};
|
||||
expect(newCard.id).toEqual(789);
|
||||
* ```
|
||||
*
|
||||
* The object returned from this function execution is a resource "class" which has "static" method
|
||||
* for each action in the definition.
|
||||
*
|
||||
* Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
|
||||
* `headers`.
|
||||
* When the data is returned from the server then the object is an instance of the resource type and
|
||||
* all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
|
||||
* operations (create, read, update, delete) on server-side data.
|
||||
|
||||
```js
|
||||
var User = $resource('/user/:userId', {userId:'@id'});
|
||||
User.get({userId:123}, function(user) {
|
||||
user.abc = true;
|
||||
user.$save();
|
||||
});
|
||||
```
|
||||
*
|
||||
* It's worth noting that the success callback for `get`, `query` and other methods gets passed
|
||||
* in the response that came from the server as well as $http header getter function, so one
|
||||
* could rewrite the above example and get access to http headers as:
|
||||
*
|
||||
```js
|
||||
var User = $resource('/user/:userId', {userId:'@id'});
|
||||
User.get({userId:123}, function(u, getResponseHeaders){
|
||||
u.abc = true;
|
||||
u.$save(function(u, putResponseHeaders) {
|
||||
//u => saved user object
|
||||
//putResponseHeaders => $http header getter
|
||||
});
|
||||
});
|
||||
```
|
||||
*
|
||||
* You can also access the raw `$http` promise via the `$promise` property on the object returned
|
||||
*
|
||||
```
|
||||
var User = $resource('/user/:userId', {userId:'@id'});
|
||||
User.get({userId:123})
|
||||
.$promise.then(function(user) {
|
||||
$scope.user = user;
|
||||
});
|
||||
```
|
||||
|
||||
* # Creating a custom 'PUT' request
|
||||
* In this example we create a custom method on our resource to make a PUT request
|
||||
* ```js
|
||||
* var app = angular.module('app', ['ngResource', 'ngRoute']);
|
||||
*
|
||||
* // Some APIs expect a PUT request in the format URL/object/ID
|
||||
* // Here we are creating an 'update' method
|
||||
* app.factory('Notes', ['$resource', function($resource) {
|
||||
* return $resource('/notes/:id', null,
|
||||
* {
|
||||
* 'update': { method:'PUT' }
|
||||
* });
|
||||
* }]);
|
||||
*
|
||||
* // In our controller we get the ID from the URL using ngRoute and $routeParams
|
||||
* // We pass in $routeParams and our Notes factory along with $scope
|
||||
* app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
|
||||
function($scope, $routeParams, Notes) {
|
||||
* // First get a note object from the factory
|
||||
* var note = Notes.get({ id:$routeParams.id });
|
||||
* $id = note.id;
|
||||
*
|
||||
* // Now call update passing in the ID first then the object you are updating
|
||||
* Notes.update({ id:$id }, note);
|
||||
*
|
||||
* // This will PUT /notes/ID with the note object in the request payload
|
||||
* }]);
|
||||
* ```
|
||||
*/
|
||||
angular.module('ngResource', ['ng']).
|
||||
provider('$resource', function() {
|
||||
var provider = this;
|
||||
|
||||
this.defaults = {
|
||||
// Strip slashes by default
|
||||
stripTrailingSlashes: true,
|
||||
|
||||
// Default actions configuration
|
||||
actions: {
|
||||
'get': {method: 'GET'},
|
||||
'save': {method: 'POST'},
|
||||
'query': {method: 'GET', isArray: true},
|
||||
'remove': {method: 'DELETE'},
|
||||
'delete': {method: 'DELETE'}
|
||||
}
|
||||
};
|
||||
|
||||
this.$get = ['$http', '$q', function($http, $q) {
|
||||
|
||||
var noop = angular.noop,
|
||||
forEach = angular.forEach,
|
||||
extend = angular.extend,
|
||||
copy = angular.copy,
|
||||
isFunction = angular.isFunction;
|
||||
|
||||
/**
|
||||
* 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(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
|
||||
}
|
||||
|
||||
function Route(template, defaults) {
|
||||
this.template = template;
|
||||
this.defaults = extend({}, provider.defaults, defaults);
|
||||
this.urlParams = {};
|
||||
}
|
||||
|
||||
Route.prototype = {
|
||||
setUrlParams: function(config, params, actionUrl) {
|
||||
var self = this,
|
||||
url = actionUrl || self.template,
|
||||
val,
|
||||
encodedVal;
|
||||
|
||||
var urlParams = self.urlParams = {};
|
||||
forEach(url.split(/\W/), function(param) {
|
||||
if (param === 'hasOwnProperty') {
|
||||
throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name.");
|
||||
}
|
||||
if (!(new RegExp("^\\d+$").test(param)) && param &&
|
||||
(new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
|
||||
urlParams[param] = true;
|
||||
}
|
||||
});
|
||||
url = url.replace(/\\:/g, ':');
|
||||
|
||||
params = params || {};
|
||||
forEach(self.urlParams, function(_, urlParam) {
|
||||
val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
|
||||
if (angular.isDefined(val) && val !== null) {
|
||||
encodedVal = encodeUriSegment(val);
|
||||
url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) {
|
||||
return encodedVal + p1;
|
||||
});
|
||||
} else {
|
||||
url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
|
||||
leadingSlashes, tail) {
|
||||
if (tail.charAt(0) == '/') {
|
||||
return tail;
|
||||
} else {
|
||||
return leadingSlashes + tail;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// strip trailing slashes and set the url (unless this behavior is specifically disabled)
|
||||
if (self.defaults.stripTrailingSlashes) {
|
||||
url = url.replace(/\/+$/, '') || '/';
|
||||
}
|
||||
|
||||
// then replace collapse `/.` if found in the last URL path segment before the query
|
||||
// E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
|
||||
url = url.replace(/\/\.(?=\w+($|\?))/, '.');
|
||||
// replace escaped `/\.` with `/.`
|
||||
config.url = url.replace(/\/\\\./, '/.');
|
||||
|
||||
|
||||
// set params - delegate param encoding to $http
|
||||
forEach(params, function(value, key) {
|
||||
if (!self.urlParams[key]) {
|
||||
config.params = config.params || {};
|
||||
config.params[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function resourceFactory(url, paramDefaults, actions, options) {
|
||||
var route = new Route(url, options);
|
||||
|
||||
actions = extend({}, provider.defaults.actions, actions);
|
||||
|
||||
function extractParams(data, actionParams) {
|
||||
var ids = {};
|
||||
actionParams = extend({}, paramDefaults, actionParams);
|
||||
forEach(actionParams, function(value, key) {
|
||||
if (isFunction(value)) { value = value(); }
|
||||
ids[key] = value && value.charAt && value.charAt(0) == '@' ?
|
||||
lookupDottedPath(data, value.substr(1)) : value;
|
||||
});
|
||||
return ids;
|
||||
}
|
||||
|
||||
function defaultResponseInterceptor(response) {
|
||||
return response.resource;
|
||||
}
|
||||
|
||||
function Resource(value) {
|
||||
shallowClearAndCopy(value || {}, this);
|
||||
}
|
||||
|
||||
Resource.prototype.toJSON = function() {
|
||||
var data = extend({}, this);
|
||||
delete data.$promise;
|
||||
delete data.$resolved;
|
||||
return data;
|
||||
};
|
||||
|
||||
forEach(actions, function(action, name) {
|
||||
var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
|
||||
|
||||
Resource[name] = function(a1, a2, a3, a4) {
|
||||
var params = {}, data, success, error;
|
||||
|
||||
/* jshint -W086 */ /* (purposefully fall through case statements) */
|
||||
switch (arguments.length) {
|
||||
case 4:
|
||||
error = a4;
|
||||
success = a3;
|
||||
//fallthrough
|
||||
case 3:
|
||||
case 2:
|
||||
if (isFunction(a2)) {
|
||||
if (isFunction(a1)) {
|
||||
success = a1;
|
||||
error = a2;
|
||||
break;
|
||||
}
|
||||
|
||||
success = a2;
|
||||
error = a3;
|
||||
//fallthrough
|
||||
} else {
|
||||
params = a1;
|
||||
data = a2;
|
||||
success = a3;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
if (isFunction(a1)) success = a1;
|
||||
else if (hasBody) data = a1;
|
||||
else params = a1;
|
||||
break;
|
||||
case 0: break;
|
||||
default:
|
||||
throw $resourceMinErr('badargs',
|
||||
"Expected up to 4 arguments [params, data, success, error], got {0} arguments",
|
||||
arguments.length);
|
||||
}
|
||||
/* jshint +W086 */ /* (purposefully fall through case statements) */
|
||||
|
||||
var isInstanceCall = this instanceof Resource;
|
||||
var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
|
||||
var httpConfig = {};
|
||||
var responseInterceptor = action.interceptor && action.interceptor.response ||
|
||||
defaultResponseInterceptor;
|
||||
var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
|
||||
undefined;
|
||||
|
||||
forEach(action, function(value, key) {
|
||||
if (key != 'params' && key != 'isArray' && key != 'interceptor') {
|
||||
httpConfig[key] = copy(value);
|
||||
}
|
||||
});
|
||||
|
||||
if (hasBody) httpConfig.data = data;
|
||||
route.setUrlParams(httpConfig,
|
||||
extend({}, extractParams(data, action.params || {}), params),
|
||||
action.url);
|
||||
|
||||
var promise = $http(httpConfig).then(function(response) {
|
||||
var data = response.data,
|
||||
promise = value.$promise;
|
||||
|
||||
if (data) {
|
||||
// Need to convert action.isArray to boolean in case it is undefined
|
||||
// jshint -W018
|
||||
if (angular.isArray(data) !== (!!action.isArray)) {
|
||||
throw $resourceMinErr('badcfg',
|
||||
'Error in resource configuration for action `{0}`. Expected response to ' +
|
||||
'contain an {1} but got an {2}', name, action.isArray ? 'array' : 'object',
|
||||
angular.isArray(data) ? 'array' : 'object');
|
||||
}
|
||||
// jshint +W018
|
||||
if (action.isArray) {
|
||||
value.length = 0;
|
||||
forEach(data, function(item) {
|
||||
if (typeof item === "object") {
|
||||
value.push(new Resource(item));
|
||||
} else {
|
||||
// Valid JSON values may be string literals, and these should not be converted
|
||||
// into objects. These items will not have access to the Resource prototype
|
||||
// methods, but unfortunately there
|
||||
value.push(item);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
shallowClearAndCopy(data, value);
|
||||
value.$promise = promise;
|
||||
}
|
||||
}
|
||||
|
||||
value.$resolved = true;
|
||||
|
||||
response.resource = value;
|
||||
|
||||
return response;
|
||||
}, function(response) {
|
||||
value.$resolved = true;
|
||||
|
||||
(error || noop)(response);
|
||||
|
||||
return $q.reject(response);
|
||||
});
|
||||
|
||||
promise = promise.then(
|
||||
function(response) {
|
||||
var value = responseInterceptor(response);
|
||||
(success || noop)(value, response.headers);
|
||||
return value;
|
||||
},
|
||||
responseErrorInterceptor);
|
||||
|
||||
if (!isInstanceCall) {
|
||||
// we are creating instance / collection
|
||||
// - set the initial promise
|
||||
// - return the instance / collection
|
||||
value.$promise = promise;
|
||||
value.$resolved = false;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// instance call
|
||||
return promise;
|
||||
};
|
||||
|
||||
|
||||
Resource.prototype['$' + name] = function(params, success, error) {
|
||||
if (isFunction(params)) {
|
||||
error = success; success = params; params = {};
|
||||
}
|
||||
var result = Resource[name].call(this, params, this, success, error);
|
||||
return result.$promise || result;
|
||||
};
|
||||
});
|
||||
|
||||
Resource.bind = function(additionalParamDefaults) {
|
||||
return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
|
||||
};
|
||||
|
||||
return Resource;
|
||||
}
|
||||
|
||||
return resourceFactory;
|
||||
}];
|
||||
});
|
||||
|
||||
|
||||
})(window, window.angular);
|
925
src/main/webapp/js/lib/angular-route.js
vendored
925
src/main/webapp/js/lib/angular-route.js
vendored
|
@ -1,925 +0,0 @@
|
|||
/**
|
||||
* @license AngularJS v1.2.24-build.423+sha.7e02fa0
|
||||
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name ngRoute
|
||||
* @description
|
||||
*
|
||||
* # ngRoute
|
||||
*
|
||||
* The `ngRoute` module provides routing and deeplinking services and directives for angular apps.
|
||||
*
|
||||
* ## Example
|
||||
* See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
|
||||
*
|
||||
*
|
||||
* <div doc-module-components="ngRoute"></div>
|
||||
*/
|
||||
/* global -ngRouteModule */
|
||||
var ngRouteModule = angular.module('ngRoute', ['ng']).
|
||||
provider('$route', $RouteProvider);
|
||||
|
||||
/**
|
||||
* @ngdoc provider
|
||||
* @name $routeProvider
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* Used for configuring routes.
|
||||
*
|
||||
* ## Example
|
||||
* See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
|
||||
*
|
||||
* ## Dependencies
|
||||
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||
*/
|
||||
function $RouteProvider(){
|
||||
function inherit(parent, extra) {
|
||||
return angular.extend(new (angular.extend(function() {}, {prototype:parent}))(), extra);
|
||||
}
|
||||
|
||||
var routes = {};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $routeProvider#when
|
||||
*
|
||||
* @param {string} path Route path (matched against `$location.path`). If `$location.path`
|
||||
* contains redundant trailing slash or is missing one, the route will still match and the
|
||||
* `$location.path` will be updated to add or drop the trailing slash to exactly match the
|
||||
* route definition.
|
||||
*
|
||||
* * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up
|
||||
* to the next slash are matched and stored in `$routeParams` under the given `name`
|
||||
* when the route matches.
|
||||
* * `path` can contain named groups starting with a colon and ending with a star:
|
||||
* e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name`
|
||||
* when the route matches.
|
||||
* * `path` can contain optional named groups with a question mark: e.g.`:name?`.
|
||||
*
|
||||
* For example, routes like `/color/:color/largecode/:largecode*\/edit` will match
|
||||
* `/color/brown/largecode/code/with/slashes/edit` and extract:
|
||||
*
|
||||
* * `color: brown`
|
||||
* * `largecode: code/with/slashes`.
|
||||
*
|
||||
*
|
||||
* @param {Object} route Mapping information to be assigned to `$route.current` on route
|
||||
* match.
|
||||
*
|
||||
* Object properties:
|
||||
*
|
||||
* - `controller` – `{(string|function()=}` – Controller fn that should be associated with
|
||||
* newly created scope or the name of a {@link angular.Module#controller registered
|
||||
* controller} if passed as a string.
|
||||
* - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be
|
||||
* published to scope under the `controllerAs` name.
|
||||
* - `template` – `{string=|function()=}` – html template as a string or a function that
|
||||
* returns an html template as a string which should be used by {@link
|
||||
* ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
|
||||
* This property takes precedence over `templateUrl`.
|
||||
*
|
||||
* If `template` is a function, it will be called with the following parameters:
|
||||
*
|
||||
* - `{Array.<Object>}` - route parameters extracted from the current
|
||||
* `$location.path()` by applying the current route
|
||||
*
|
||||
* - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
|
||||
* template that should be used by {@link ngRoute.directive:ngView ngView}.
|
||||
*
|
||||
* If `templateUrl` is a function, it will be called with the following parameters:
|
||||
*
|
||||
* - `{Array.<Object>}` - route parameters extracted from the current
|
||||
* `$location.path()` by applying the current route
|
||||
*
|
||||
* - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
|
||||
* be injected into the controller. If any of these dependencies are promises, the router
|
||||
* will wait for them all to be resolved or one to be rejected before the controller is
|
||||
* instantiated.
|
||||
* If all the promises are resolved successfully, the values of the resolved promises are
|
||||
* injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is
|
||||
* fired. If any of the promises are rejected the
|
||||
* {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired. The map object
|
||||
* is:
|
||||
*
|
||||
* - `key` – `{string}`: a name of a dependency to be injected into the controller.
|
||||
* - `factory` - `{string|function}`: If `string` then it is an alias for a service.
|
||||
* Otherwise if function, then it is {@link auto.$injector#invoke injected}
|
||||
* and the return value is treated as the dependency. If the result is a promise, it is
|
||||
* resolved before its value is injected into the controller. Be aware that
|
||||
* `ngRoute.$routeParams` will still refer to the previous route within these resolve
|
||||
* functions. Use `$route.current.params` to access the new route parameters, instead.
|
||||
*
|
||||
* - `redirectTo` – {(string|function())=} – value to update
|
||||
* {@link ng.$location $location} path with and trigger route redirection.
|
||||
*
|
||||
* If `redirectTo` is a function, it will be called with the following parameters:
|
||||
*
|
||||
* - `{Object.<string>}` - route parameters extracted from the current
|
||||
* `$location.path()` by applying the current route templateUrl.
|
||||
* - `{string}` - current `$location.path()`
|
||||
* - `{Object}` - current `$location.search()`
|
||||
*
|
||||
* The custom `redirectTo` function is expected to return a string which will be used
|
||||
* to update `$location.path()` and `$location.search()`.
|
||||
*
|
||||
* - `[reloadOnSearch=true]` - {boolean=} - reload route when only `$location.search()`
|
||||
* or `$location.hash()` changes.
|
||||
*
|
||||
* If the option is set to `false` and url in the browser changes, then
|
||||
* `$routeUpdate` event is broadcasted on the root scope.
|
||||
*
|
||||
* - `[caseInsensitiveMatch=false]` - {boolean=} - match routes without being case sensitive
|
||||
*
|
||||
* If the option is set to `true`, then the particular route can be matched without being
|
||||
* case sensitive
|
||||
*
|
||||
* @returns {Object} self
|
||||
*
|
||||
* @description
|
||||
* Adds a new route definition to the `$route` service.
|
||||
*/
|
||||
this.when = function(path, route) {
|
||||
routes[path] = angular.extend(
|
||||
{reloadOnSearch: true},
|
||||
route,
|
||||
path && pathRegExp(path, route)
|
||||
);
|
||||
|
||||
// create redirection for trailing slashes
|
||||
if (path) {
|
||||
var redirectPath = (path[path.length-1] == '/')
|
||||
? path.substr(0, path.length-1)
|
||||
: path +'/';
|
||||
|
||||
routes[redirectPath] = angular.extend(
|
||||
{redirectTo: path},
|
||||
pathRegExp(redirectPath, route)
|
||||
);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param path {string} path
|
||||
* @param opts {Object} options
|
||||
* @return {?Object}
|
||||
*
|
||||
* @description
|
||||
* Normalizes the given path, returning a regular expression
|
||||
* and the original path.
|
||||
*
|
||||
* Inspired by pathRexp in visionmedia/express/lib/utils.js.
|
||||
*/
|
||||
function pathRegExp(path, opts) {
|
||||
var insensitive = opts.caseInsensitiveMatch,
|
||||
ret = {
|
||||
originalPath: path,
|
||||
regexp: path
|
||||
},
|
||||
keys = ret.keys = [];
|
||||
|
||||
path = path
|
||||
.replace(/([().])/g, '\\$1')
|
||||
.replace(/(\/)?:(\w+)([\?\*])?/g, function(_, slash, key, option){
|
||||
var optional = option === '?' ? option : null;
|
||||
var star = option === '*' ? option : null;
|
||||
keys.push({ name: key, optional: !!optional });
|
||||
slash = slash || '';
|
||||
return ''
|
||||
+ (optional ? '' : slash)
|
||||
+ '(?:'
|
||||
+ (optional ? slash : '')
|
||||
+ (star && '(.+?)' || '([^/]+)')
|
||||
+ (optional || '')
|
||||
+ ')'
|
||||
+ (optional || '');
|
||||
})
|
||||
.replace(/([\/$\*])/g, '\\$1');
|
||||
|
||||
ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : '');
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $routeProvider#otherwise
|
||||
*
|
||||
* @description
|
||||
* Sets route definition that will be used on route change when no other route definition
|
||||
* is matched.
|
||||
*
|
||||
* @param {Object} params Mapping information to be assigned to `$route.current`.
|
||||
* @returns {Object} self
|
||||
*/
|
||||
this.otherwise = function(params) {
|
||||
this.when(null, params);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
this.$get = ['$rootScope',
|
||||
'$location',
|
||||
'$routeParams',
|
||||
'$q',
|
||||
'$injector',
|
||||
'$http',
|
||||
'$templateCache',
|
||||
'$sce',
|
||||
function($rootScope, $location, $routeParams, $q, $injector, $http, $templateCache, $sce) {
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name $route
|
||||
* @requires $location
|
||||
* @requires $routeParams
|
||||
*
|
||||
* @property {Object} current Reference to the current route definition.
|
||||
* The route definition contains:
|
||||
*
|
||||
* - `controller`: The controller constructor as define in route definition.
|
||||
* - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for
|
||||
* controller instantiation. The `locals` contain
|
||||
* the resolved values of the `resolve` map. Additionally the `locals` also contain:
|
||||
*
|
||||
* - `$scope` - The current route scope.
|
||||
* - `$template` - The current route template HTML.
|
||||
*
|
||||
* @property {Object} routes Object with all route configuration Objects as its properties.
|
||||
*
|
||||
* @description
|
||||
* `$route` is used for deep-linking URLs to controllers and views (HTML partials).
|
||||
* It watches `$location.url()` and tries to map the path to an existing route definition.
|
||||
*
|
||||
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||
*
|
||||
* You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API.
|
||||
*
|
||||
* The `$route` service is typically used in conjunction with the
|
||||
* {@link ngRoute.directive:ngView `ngView`} directive and the
|
||||
* {@link ngRoute.$routeParams `$routeParams`} service.
|
||||
*
|
||||
* @example
|
||||
* This example shows how changing the URL hash causes the `$route` to match a route against the
|
||||
* URL, and the `ngView` pulls in the partial.
|
||||
*
|
||||
* Note that this example is using {@link ng.directive:script inlined templates}
|
||||
* to get it working on jsfiddle as well.
|
||||
*
|
||||
* <example name="$route-service" module="ngRouteExample"
|
||||
* deps="angular-route.js" fixBase="true">
|
||||
* <file name="index.html">
|
||||
* <div ng-controller="MainController">
|
||||
* Choose:
|
||||
* <a href="Book/Moby">Moby</a> |
|
||||
* <a href="Book/Moby/ch/1">Moby: Ch1</a> |
|
||||
* <a href="Book/Gatsby">Gatsby</a> |
|
||||
* <a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
|
||||
* <a href="Book/Scarlet">Scarlet Letter</a><br/>
|
||||
*
|
||||
* <div ng-view></div>
|
||||
*
|
||||
* <hr />
|
||||
*
|
||||
* <pre>$location.path() = {{$location.path()}}</pre>
|
||||
* <pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
|
||||
* <pre>$route.current.params = {{$route.current.params}}</pre>
|
||||
* <pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
|
||||
* <pre>$routeParams = {{$routeParams}}</pre>
|
||||
* </div>
|
||||
* </file>
|
||||
*
|
||||
* <file name="book.html">
|
||||
* controller: {{name}}<br />
|
||||
* Book Id: {{params.bookId}}<br />
|
||||
* </file>
|
||||
*
|
||||
* <file name="chapter.html">
|
||||
* controller: {{name}}<br />
|
||||
* Book Id: {{params.bookId}}<br />
|
||||
* Chapter Id: {{params.chapterId}}
|
||||
* </file>
|
||||
*
|
||||
* <file name="script.js">
|
||||
* angular.module('ngRouteExample', ['ngRoute'])
|
||||
*
|
||||
* .controller('MainController', function($scope, $route, $routeParams, $location) {
|
||||
* $scope.$route = $route;
|
||||
* $scope.$location = $location;
|
||||
* $scope.$routeParams = $routeParams;
|
||||
* })
|
||||
*
|
||||
* .controller('BookController', function($scope, $routeParams) {
|
||||
* $scope.name = "BookController";
|
||||
* $scope.params = $routeParams;
|
||||
* })
|
||||
*
|
||||
* .controller('ChapterController', function($scope, $routeParams) {
|
||||
* $scope.name = "ChapterController";
|
||||
* $scope.params = $routeParams;
|
||||
* })
|
||||
*
|
||||
* .config(function($routeProvider, $locationProvider) {
|
||||
* $routeProvider
|
||||
* .when('/Book/:bookId', {
|
||||
* templateUrl: 'book.html',
|
||||
* controller: 'BookController',
|
||||
* resolve: {
|
||||
* // I will cause a 1 second delay
|
||||
* delay: function($q, $timeout) {
|
||||
* var delay = $q.defer();
|
||||
* $timeout(delay.resolve, 1000);
|
||||
* return delay.promise;
|
||||
* }
|
||||
* }
|
||||
* })
|
||||
* .when('/Book/:bookId/ch/:chapterId', {
|
||||
* templateUrl: 'chapter.html',
|
||||
* controller: 'ChapterController'
|
||||
* });
|
||||
*
|
||||
* // configure html5 to get links working on jsfiddle
|
||||
* $locationProvider.html5Mode(true);
|
||||
* });
|
||||
*
|
||||
* </file>
|
||||
*
|
||||
* <file name="protractor.js" type="protractor">
|
||||
* it('should load and compile correct template', function() {
|
||||
* element(by.linkText('Moby: Ch1')).click();
|
||||
* var content = element(by.css('[ng-view]')).getText();
|
||||
* expect(content).toMatch(/controller\: ChapterController/);
|
||||
* expect(content).toMatch(/Book Id\: Moby/);
|
||||
* expect(content).toMatch(/Chapter Id\: 1/);
|
||||
*
|
||||
* element(by.partialLinkText('Scarlet')).click();
|
||||
*
|
||||
* content = element(by.css('[ng-view]')).getText();
|
||||
* expect(content).toMatch(/controller\: BookController/);
|
||||
* expect(content).toMatch(/Book Id\: Scarlet/);
|
||||
* });
|
||||
* </file>
|
||||
* </example>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name $route#$routeChangeStart
|
||||
* @eventType broadcast on root scope
|
||||
* @description
|
||||
* Broadcasted before a route change. At this point the route services starts
|
||||
* resolving all of the dependencies needed for the route change to occur.
|
||||
* Typically this involves fetching the view template as well as any dependencies
|
||||
* defined in `resolve` route property. Once all of the dependencies are resolved
|
||||
* `$routeChangeSuccess` is fired.
|
||||
*
|
||||
* @param {Object} angularEvent Synthetic event object.
|
||||
* @param {Route} next Future route information.
|
||||
* @param {Route} current Current route information.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name $route#$routeChangeSuccess
|
||||
* @eventType broadcast on root scope
|
||||
* @description
|
||||
* Broadcasted after a route dependencies are resolved.
|
||||
* {@link ngRoute.directive:ngView ngView} listens for the directive
|
||||
* to instantiate the controller and render the view.
|
||||
*
|
||||
* @param {Object} angularEvent Synthetic event object.
|
||||
* @param {Route} current Current route information.
|
||||
* @param {Route|Undefined} previous Previous route information, or undefined if current is
|
||||
* first route entered.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name $route#$routeChangeError
|
||||
* @eventType broadcast on root scope
|
||||
* @description
|
||||
* Broadcasted if any of the resolve promises are rejected.
|
||||
*
|
||||
* @param {Object} angularEvent Synthetic event object
|
||||
* @param {Route} current Current route information.
|
||||
* @param {Route} previous Previous route information.
|
||||
* @param {Route} rejection Rejection of the promise. Usually the error of the failed promise.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name $route#$routeUpdate
|
||||
* @eventType broadcast on root scope
|
||||
* @description
|
||||
*
|
||||
* The `reloadOnSearch` property has been set to false, and we are reusing the same
|
||||
* instance of the Controller.
|
||||
*/
|
||||
|
||||
var forceReload = false,
|
||||
$route = {
|
||||
routes: routes,
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $route#reload
|
||||
*
|
||||
* @description
|
||||
* Causes `$route` service to reload the current route even if
|
||||
* {@link ng.$location $location} hasn't changed.
|
||||
*
|
||||
* As a result of that, {@link ngRoute.directive:ngView ngView}
|
||||
* creates new scope, reinstantiates the controller.
|
||||
*/
|
||||
reload: function() {
|
||||
forceReload = true;
|
||||
$rootScope.$evalAsync(updateRoute);
|
||||
}
|
||||
};
|
||||
|
||||
$rootScope.$on('$locationChangeSuccess', updateRoute);
|
||||
|
||||
return $route;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @param on {string} current url
|
||||
* @param route {Object} route regexp to match the url against
|
||||
* @return {?Object}
|
||||
*
|
||||
* @description
|
||||
* Check if the route matches the current url.
|
||||
*
|
||||
* Inspired by match in
|
||||
* visionmedia/express/lib/router/router.js.
|
||||
*/
|
||||
function switchRouteMatcher(on, route) {
|
||||
var keys = route.keys,
|
||||
params = {};
|
||||
|
||||
if (!route.regexp) return null;
|
||||
|
||||
var m = route.regexp.exec(on);
|
||||
if (!m) return null;
|
||||
|
||||
for (var i = 1, len = m.length; i < len; ++i) {
|
||||
var key = keys[i - 1];
|
||||
|
||||
var val = m[i];
|
||||
|
||||
if (key && val) {
|
||||
params[key.name] = val;
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
function updateRoute() {
|
||||
var next = parseRoute(),
|
||||
last = $route.current;
|
||||
|
||||
if (next && last && next.$$route === last.$$route
|
||||
&& angular.equals(next.pathParams, last.pathParams)
|
||||
&& !next.reloadOnSearch && !forceReload) {
|
||||
last.params = next.params;
|
||||
angular.copy(last.params, $routeParams);
|
||||
$rootScope.$broadcast('$routeUpdate', last);
|
||||
} else if (next || last) {
|
||||
forceReload = false;
|
||||
$rootScope.$broadcast('$routeChangeStart', next, last);
|
||||
$route.current = next;
|
||||
if (next) {
|
||||
if (next.redirectTo) {
|
||||
if (angular.isString(next.redirectTo)) {
|
||||
$location.path(interpolate(next.redirectTo, next.params)).search(next.params)
|
||||
.replace();
|
||||
} else {
|
||||
$location.url(next.redirectTo(next.pathParams, $location.path(), $location.search()))
|
||||
.replace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$q.when(next).
|
||||
then(function() {
|
||||
if (next) {
|
||||
var locals = angular.extend({}, next.resolve),
|
||||
template, templateUrl;
|
||||
|
||||
angular.forEach(locals, function(value, key) {
|
||||
locals[key] = angular.isString(value) ?
|
||||
$injector.get(value) : $injector.invoke(value);
|
||||
});
|
||||
|
||||
if (angular.isDefined(template = next.template)) {
|
||||
if (angular.isFunction(template)) {
|
||||
template = template(next.params);
|
||||
}
|
||||
} else if (angular.isDefined(templateUrl = next.templateUrl)) {
|
||||
if (angular.isFunction(templateUrl)) {
|
||||
templateUrl = templateUrl(next.params);
|
||||
}
|
||||
templateUrl = $sce.getTrustedResourceUrl(templateUrl);
|
||||
if (angular.isDefined(templateUrl)) {
|
||||
next.loadedTemplateUrl = templateUrl;
|
||||
template = $http.get(templateUrl, {cache: $templateCache}).
|
||||
then(function(response) { return response.data; });
|
||||
}
|
||||
}
|
||||
if (angular.isDefined(template)) {
|
||||
locals['$template'] = template;
|
||||
}
|
||||
return $q.all(locals);
|
||||
}
|
||||
}).
|
||||
// after route change
|
||||
then(function(locals) {
|
||||
if (next == $route.current) {
|
||||
if (next) {
|
||||
next.locals = locals;
|
||||
angular.copy(next.params, $routeParams);
|
||||
}
|
||||
$rootScope.$broadcast('$routeChangeSuccess', next, last);
|
||||
}
|
||||
}, function(error) {
|
||||
if (next == $route.current) {
|
||||
$rootScope.$broadcast('$routeChangeError', next, last, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @returns {Object} the current active route, by matching it against the URL
|
||||
*/
|
||||
function parseRoute() {
|
||||
// Match a route
|
||||
var params, match;
|
||||
angular.forEach(routes, function(route, path) {
|
||||
if (!match && (params = switchRouteMatcher($location.path(), route))) {
|
||||
match = inherit(route, {
|
||||
params: angular.extend({}, $location.search(), params),
|
||||
pathParams: params});
|
||||
match.$$route = route;
|
||||
}
|
||||
});
|
||||
// No route matched; fallback to "otherwise" route
|
||||
return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} interpolation of the redirect path with the parameters
|
||||
*/
|
||||
function interpolate(string, params) {
|
||||
var result = [];
|
||||
angular.forEach((string||'').split(':'), function(segment, i) {
|
||||
if (i === 0) {
|
||||
result.push(segment);
|
||||
} else {
|
||||
var segmentMatch = segment.match(/(\w+)(.*)/);
|
||||
var key = segmentMatch[1];
|
||||
result.push(params[key]);
|
||||
result.push(segmentMatch[2] || '');
|
||||
delete params[key];
|
||||
}
|
||||
});
|
||||
return result.join('');
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
ngRouteModule.provider('$routeParams', $RouteParamsProvider);
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name $routeParams
|
||||
* @requires $route
|
||||
*
|
||||
* @description
|
||||
* The `$routeParams` service allows you to retrieve the current set of route parameters.
|
||||
*
|
||||
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||
*
|
||||
* The route parameters are a combination of {@link ng.$location `$location`}'s
|
||||
* {@link ng.$location#search `search()`} and {@link ng.$location#path `path()`}.
|
||||
* The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched.
|
||||
*
|
||||
* In case of parameter name collision, `path` params take precedence over `search` params.
|
||||
*
|
||||
* The service guarantees that the identity of the `$routeParams` object will remain unchanged
|
||||
* (but its properties will likely change) even when a route change occurs.
|
||||
*
|
||||
* Note that the `$routeParams` are only updated *after* a route change completes successfully.
|
||||
* This means that you cannot rely on `$routeParams` being correct in route resolve functions.
|
||||
* Instead you can use `$route.current.params` to access the new route's parameters.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* // Given:
|
||||
* // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
|
||||
* // Route: /Chapter/:chapterId/Section/:sectionId
|
||||
* //
|
||||
* // Then
|
||||
* $routeParams ==> {chapterId:'1', sectionId:'2', search:'moby'}
|
||||
* ```
|
||||
*/
|
||||
function $RouteParamsProvider() {
|
||||
this.$get = function() { return {}; };
|
||||
}
|
||||
|
||||
ngRouteModule.directive('ngView', ngViewFactory);
|
||||
ngRouteModule.directive('ngView', ngViewFillContentFactory);
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngView
|
||||
* @restrict ECA
|
||||
*
|
||||
* @description
|
||||
* # Overview
|
||||
* `ngView` is a directive that complements the {@link ngRoute.$route $route} service by
|
||||
* including the rendered template of the current route into the main layout (`index.html`) file.
|
||||
* Every time the current route changes, the included view changes with it according to the
|
||||
* configuration of the `$route` service.
|
||||
*
|
||||
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||
*
|
||||
* @animations
|
||||
* enter - animation is used to bring new content into the browser.
|
||||
* leave - animation is used to animate existing content away.
|
||||
*
|
||||
* The enter and leave animation occur concurrently.
|
||||
*
|
||||
* @scope
|
||||
* @priority 400
|
||||
* @param {string=} onload Expression to evaluate whenever the view updates.
|
||||
*
|
||||
* @param {string=} autoscroll Whether `ngView` should call {@link ng.$anchorScroll
|
||||
* $anchorScroll} to scroll the viewport after the view is updated.
|
||||
*
|
||||
* - If the attribute is not set, disable scrolling.
|
||||
* - If the attribute is set without value, enable scrolling.
|
||||
* - Otherwise enable scrolling only if the `autoscroll` attribute value evaluated
|
||||
* as an expression yields a truthy value.
|
||||
* @example
|
||||
<example name="ngView-directive" module="ngViewExample"
|
||||
deps="angular-route.js;angular-animate.js"
|
||||
animations="true" fixBase="true">
|
||||
<file name="index.html">
|
||||
<div ng-controller="MainCtrl as main">
|
||||
Choose:
|
||||
<a href="Book/Moby">Moby</a> |
|
||||
<a href="Book/Moby/ch/1">Moby: Ch1</a> |
|
||||
<a href="Book/Gatsby">Gatsby</a> |
|
||||
<a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
|
||||
<a href="Book/Scarlet">Scarlet Letter</a><br/>
|
||||
|
||||
<div class="view-animate-container">
|
||||
<div ng-view class="view-animate"></div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<pre>$location.path() = {{main.$location.path()}}</pre>
|
||||
<pre>$route.current.templateUrl = {{main.$route.current.templateUrl}}</pre>
|
||||
<pre>$route.current.params = {{main.$route.current.params}}</pre>
|
||||
<pre>$route.current.scope.name = {{main.$route.current.scope.name}}</pre>
|
||||
<pre>$routeParams = {{main.$routeParams}}</pre>
|
||||
</div>
|
||||
</file>
|
||||
|
||||
<file name="book.html">
|
||||
<div>
|
||||
controller: {{book.name}}<br />
|
||||
Book Id: {{book.params.bookId}}<br />
|
||||
</div>
|
||||
</file>
|
||||
|
||||
<file name="chapter.html">
|
||||
<div>
|
||||
controller: {{chapter.name}}<br />
|
||||
Book Id: {{chapter.params.bookId}}<br />
|
||||
Chapter Id: {{chapter.params.chapterId}}
|
||||
</div>
|
||||
</file>
|
||||
|
||||
<file name="animations.css">
|
||||
.view-animate-container {
|
||||
position:relative;
|
||||
height:100px!important;
|
||||
position:relative;
|
||||
background:white;
|
||||
border:1px solid black;
|
||||
height:40px;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.view-animate {
|
||||
padding:10px;
|
||||
}
|
||||
|
||||
.view-animate.ng-enter, .view-animate.ng-leave {
|
||||
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
||||
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
||||
|
||||
display:block;
|
||||
width:100%;
|
||||
border-left:1px solid black;
|
||||
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
right:0;
|
||||
bottom:0;
|
||||
padding:10px;
|
||||
}
|
||||
|
||||
.view-animate.ng-enter {
|
||||
left:100%;
|
||||
}
|
||||
.view-animate.ng-enter.ng-enter-active {
|
||||
left:0;
|
||||
}
|
||||
.view-animate.ng-leave.ng-leave-active {
|
||||
left:-100%;
|
||||
}
|
||||
</file>
|
||||
|
||||
<file name="script.js">
|
||||
angular.module('ngViewExample', ['ngRoute', 'ngAnimate'])
|
||||
.config(['$routeProvider', '$locationProvider',
|
||||
function($routeProvider, $locationProvider) {
|
||||
$routeProvider
|
||||
.when('/Book/:bookId', {
|
||||
templateUrl: 'book.html',
|
||||
controller: 'BookCtrl',
|
||||
controllerAs: 'book'
|
||||
})
|
||||
.when('/Book/:bookId/ch/:chapterId', {
|
||||
templateUrl: 'chapter.html',
|
||||
controller: 'ChapterCtrl',
|
||||
controllerAs: 'chapter'
|
||||
});
|
||||
|
||||
// configure html5 to get links working on jsfiddle
|
||||
$locationProvider.html5Mode(true);
|
||||
}])
|
||||
.controller('MainCtrl', ['$route', '$routeParams', '$location',
|
||||
function($route, $routeParams, $location) {
|
||||
this.$route = $route;
|
||||
this.$location = $location;
|
||||
this.$routeParams = $routeParams;
|
||||
}])
|
||||
.controller('BookCtrl', ['$routeParams', function($routeParams) {
|
||||
this.name = "BookCtrl";
|
||||
this.params = $routeParams;
|
||||
}])
|
||||
.controller('ChapterCtrl', ['$routeParams', function($routeParams) {
|
||||
this.name = "ChapterCtrl";
|
||||
this.params = $routeParams;
|
||||
}]);
|
||||
|
||||
</file>
|
||||
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should load and compile correct template', function() {
|
||||
element(by.linkText('Moby: Ch1')).click();
|
||||
var content = element(by.css('[ng-view]')).getText();
|
||||
expect(content).toMatch(/controller\: ChapterCtrl/);
|
||||
expect(content).toMatch(/Book Id\: Moby/);
|
||||
expect(content).toMatch(/Chapter Id\: 1/);
|
||||
|
||||
element(by.partialLinkText('Scarlet')).click();
|
||||
|
||||
content = element(by.css('[ng-view]')).getText();
|
||||
expect(content).toMatch(/controller\: BookCtrl/);
|
||||
expect(content).toMatch(/Book Id\: Scarlet/);
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name ngView#$viewContentLoaded
|
||||
* @eventType emit on the current ngView scope
|
||||
* @description
|
||||
* Emitted every time the ngView content is reloaded.
|
||||
*/
|
||||
ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate'];
|
||||
function ngViewFactory( $route, $anchorScroll, $animate) {
|
||||
return {
|
||||
restrict: 'ECA',
|
||||
terminal: true,
|
||||
priority: 400,
|
||||
transclude: 'element',
|
||||
link: function(scope, $element, attr, ctrl, $transclude) {
|
||||
var currentScope,
|
||||
currentElement,
|
||||
previousElement,
|
||||
autoScrollExp = attr.autoscroll,
|
||||
onloadExp = attr.onload || '';
|
||||
|
||||
scope.$on('$routeChangeSuccess', update);
|
||||
update();
|
||||
|
||||
function cleanupLastView() {
|
||||
if(previousElement) {
|
||||
previousElement.remove();
|
||||
previousElement = null;
|
||||
}
|
||||
if(currentScope) {
|
||||
currentScope.$destroy();
|
||||
currentScope = null;
|
||||
}
|
||||
if(currentElement) {
|
||||
$animate.leave(currentElement, function() {
|
||||
previousElement = null;
|
||||
});
|
||||
previousElement = currentElement;
|
||||
currentElement = null;
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
var locals = $route.current && $route.current.locals,
|
||||
template = locals && locals.$template;
|
||||
|
||||
if (angular.isDefined(template)) {
|
||||
var newScope = scope.$new();
|
||||
var current = $route.current;
|
||||
|
||||
// Note: This will also link all children of ng-view that were contained in the original
|
||||
// html. If that content contains controllers, ... they could pollute/change the scope.
|
||||
// However, using ng-view on an element with additional content does not make sense...
|
||||
// Note: We can't remove them in the cloneAttchFn of $transclude as that
|
||||
// function is called before linking the content, which would apply child
|
||||
// directives to non existing elements.
|
||||
var clone = $transclude(newScope, function(clone) {
|
||||
$animate.enter(clone, null, currentElement || $element, function onNgViewEnter () {
|
||||
if (angular.isDefined(autoScrollExp)
|
||||
&& (!autoScrollExp || scope.$eval(autoScrollExp))) {
|
||||
$anchorScroll();
|
||||
}
|
||||
});
|
||||
cleanupLastView();
|
||||
});
|
||||
|
||||
currentElement = clone;
|
||||
currentScope = current.scope = newScope;
|
||||
currentScope.$emit('$viewContentLoaded');
|
||||
currentScope.$eval(onloadExp);
|
||||
} else {
|
||||
cleanupLastView();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// This directive is called during the $transclude call of the first `ngView` directive.
|
||||
// It will replace and compile the content of the element with the loaded template.
|
||||
// We need this directive so that the element content is already filled when
|
||||
// the link function of another directive on the same element as ngView
|
||||
// is called.
|
||||
ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route'];
|
||||
function ngViewFillContentFactory($compile, $controller, $route) {
|
||||
return {
|
||||
restrict: 'ECA',
|
||||
priority: -400,
|
||||
link: function(scope, $element) {
|
||||
var current = $route.current,
|
||||
locals = current.locals;
|
||||
|
||||
$element.html(locals.$template);
|
||||
|
||||
var link = $compile($element.contents());
|
||||
|
||||
if (current.controller) {
|
||||
locals.$scope = scope;
|
||||
var controller = $controller(current.controller, locals);
|
||||
if (current.controllerAs) {
|
||||
scope[current.controllerAs] = controller;
|
||||
}
|
||||
$element.data('$ngControllerController', controller);
|
||||
$element.children().data('$ngControllerController', controller);
|
||||
}
|
||||
|
||||
link(scope);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
})(window, window.angular);
|
174
src/main/webapp/js/lib/angular-toaster.js
vendored
174
src/main/webapp/js/lib/angular-toaster.js
vendored
|
@ -1,174 +0,0 @@
|
|||
(function(window, angular, undefined) {'use strict';
|
||||
|
||||
/*
|
||||
* AngularJS Toaster
|
||||
* Version: 0.4.4
|
||||
*
|
||||
* Copyright 2013 Jiri Kavulak.
|
||||
* All Rights Reserved.
|
||||
* Use, reproduction, distribution, and modification of this code is subject to the terms and
|
||||
* conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
* Author: Jiri Kavulak
|
||||
* Related to project of John Papa and Hans Fjällemark
|
||||
*/
|
||||
|
||||
angular.module('toaster', ['ngAnimate'])
|
||||
.service('toaster', ['$rootScope', function ($rootScope) {
|
||||
this.pop = function (type, title, body, timeout, bodyOutputType) {
|
||||
this.toast = {
|
||||
type: type,
|
||||
title: title,
|
||||
body: body,
|
||||
timeout: timeout,
|
||||
bodyOutputType: bodyOutputType
|
||||
};
|
||||
$rootScope.$broadcast('toaster-newToast');
|
||||
};
|
||||
|
||||
this.clear = function () {
|
||||
$rootScope.$broadcast('toaster-clearToasts');
|
||||
};
|
||||
}])
|
||||
.constant('toasterConfig', {
|
||||
'limit': 0, // limits max number of toasts
|
||||
'tap-to-dismiss': true,
|
||||
'newest-on-top': true,
|
||||
//'fade-in': 1000, // done in css
|
||||
//'on-fade-in': undefined, // not implemented
|
||||
//'fade-out': 1000, // done in css
|
||||
// 'on-fade-out': undefined, // not implemented
|
||||
//'extended-time-out': 1000, // not implemented
|
||||
'time-out': 5000, // Set timeOut and extendedTimeout to 0 to make it sticky
|
||||
'icon-classes': {
|
||||
error: 'toast-error',
|
||||
info: 'toast-info',
|
||||
success: 'toast-success',
|
||||
warning: 'toast-warning'
|
||||
},
|
||||
'body-output-type': '', // Options: '', 'trustedHtml', 'template'
|
||||
'body-template': 'toasterBodyTmpl.html',
|
||||
'icon-class': 'toast-info',
|
||||
'position-class': 'toast-top-right',
|
||||
'title-class': 'toast-title',
|
||||
'message-class': 'toast-message'
|
||||
})
|
||||
.directive('toasterContainer', ['$compile', '$timeout', '$sce', 'toasterConfig', 'toaster',
|
||||
function ($compile, $timeout, $sce, toasterConfig, toaster) {
|
||||
return {
|
||||
replace: true,
|
||||
restrict: 'EA',
|
||||
link: function (scope, elm, attrs) {
|
||||
|
||||
var id = 0;
|
||||
|
||||
var mergedConfig = toasterConfig;
|
||||
if (attrs.toasterOptions) {
|
||||
angular.extend(mergedConfig, scope.$eval(attrs.toasterOptions));
|
||||
}
|
||||
|
||||
scope.config = {
|
||||
position: mergedConfig['position-class'],
|
||||
title: mergedConfig['title-class'],
|
||||
message: mergedConfig['message-class'],
|
||||
tap: mergedConfig['tap-to-dismiss']
|
||||
};
|
||||
|
||||
scope.configureTimer = function configureTimer(toast) {
|
||||
var timeout = typeof (toast.timeout) == "number" ? toast.timeout : mergedConfig['time-out'];
|
||||
if (timeout > 0)
|
||||
setTimeout(toast, timeout);
|
||||
};
|
||||
|
||||
function addToast(toast) {
|
||||
toast.type = mergedConfig['icon-classes'][toast.type];
|
||||
if (!toast.type)
|
||||
toast.type = mergedConfig['icon-class'];
|
||||
|
||||
id++;
|
||||
angular.extend(toast, { id: id });
|
||||
|
||||
// Set the toast.bodyOutputType to the default if it isn't set
|
||||
toast.bodyOutputType = toast.bodyOutputType || mergedConfig['body-output-type']
|
||||
switch (toast.bodyOutputType) {
|
||||
case 'trustedHtml':
|
||||
toast.html = $sce.trustAsHtml(toast.body);
|
||||
break;
|
||||
case 'template':
|
||||
toast.bodyTemplate = toast.body || mergedConfig['body-template'];
|
||||
break;
|
||||
}
|
||||
|
||||
scope.configureTimer(toast);
|
||||
|
||||
if (mergedConfig['newest-on-top'] === true) {
|
||||
scope.toasters.unshift(toast);
|
||||
if (mergedConfig['limit'] > 0 && scope.toasters.length > mergedConfig['limit']) {
|
||||
scope.toasters.pop();
|
||||
}
|
||||
} else {
|
||||
scope.toasters.push(toast);
|
||||
if (mergedConfig['limit'] > 0 && scope.toasters.length > mergedConfig['limit']) {
|
||||
scope.toasters.shift();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setTimeout(toast, time) {
|
||||
toast.timeout = $timeout(function () {
|
||||
scope.removeToast(toast.id);
|
||||
}, time);
|
||||
}
|
||||
|
||||
scope.toasters = [];
|
||||
scope.$on('toaster-newToast', function () {
|
||||
addToast(toaster.toast);
|
||||
});
|
||||
|
||||
scope.$on('toaster-clearToasts', function () {
|
||||
scope.toasters.splice(0, scope.toasters.length);
|
||||
});
|
||||
},
|
||||
controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
|
||||
|
||||
$scope.stopTimer = function (toast) {
|
||||
if (toast.timeout) {
|
||||
$timeout.cancel(toast.timeout);
|
||||
toast.timeout = null;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.restartTimer = function (toast) {
|
||||
if (!toast.timeout)
|
||||
$scope.configureTimer(toast);
|
||||
};
|
||||
|
||||
$scope.removeToast = function (id) {
|
||||
var i = 0;
|
||||
for (i; i < $scope.toasters.length; i++) {
|
||||
if ($scope.toasters[i].id === id)
|
||||
break;
|
||||
}
|
||||
$scope.toasters.splice(i, 1);
|
||||
};
|
||||
|
||||
$scope.remove = function (id) {
|
||||
if ($scope.config.tap === true) {
|
||||
$scope.removeToast(id);
|
||||
}
|
||||
};
|
||||
}],
|
||||
template:
|
||||
'<div id="toast-container" ng-class="config.position">' +
|
||||
'<div ng-repeat="toaster in toasters" class="toast" ng-class="toaster.type" ng-click="remove(toaster.id)" ng-mouseover="stopTimer(toaster)" ng-mouseout="restartTimer(toaster)">' +
|
||||
'<div ng-class="config.title">{{toaster.title}}</div>' +
|
||||
'<div ng-class="config.message" ng-switch on="toaster.bodyOutputType">' +
|
||||
'<div ng-switch-when="trustedHtml" ng-bind-html="toaster.html"></div>' +
|
||||
'<div ng-switch-when="template"><div ng-include="toaster.bodyTemplate"></div></div>' +
|
||||
'<div ng-switch-default >{{toaster.body}}</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
};
|
||||
}]);
|
||||
})(window, window.angular);
|
13242
src/main/webapp/js/lib/angular.js
vendored
13242
src/main/webapp/js/lib/angular.js
vendored
File diff suppressed because it is too large
Load diff
502
src/main/webapp/js/lib/angularAMD.js
vendored
502
src/main/webapp/js/lib/angularAMD.js
vendored
|
@ -1,502 +0,0 @@
|
|||
/*!
|
||||
angularAMD v0.2.1
|
||||
(c) 2013-2014 Marcos Lin https://github.com/marcoslin/
|
||||
License: MIT
|
||||
*/
|
||||
define(function () {
|
||||
'use strict';
|
||||
var bootstrapped = false,
|
||||
|
||||
// Used in .bootstrap
|
||||
app_name,
|
||||
orig_app,
|
||||
alt_app,
|
||||
run_injector,
|
||||
config_injector,
|
||||
app_cached_providers = {},
|
||||
|
||||
// Used in setAlternateAngular(), alt_angular is set to become angular.module
|
||||
orig_angular,
|
||||
alt_angular,
|
||||
|
||||
// Object that wrap the provider methods that enables lazy loading
|
||||
onDemandLoader = {},
|
||||
preBootstrapLoaderQueue = [],
|
||||
|
||||
// Used in setAlternateAngular() and .processQueue
|
||||
alternate_modules = {},
|
||||
alternate_modules_tracker = {},
|
||||
alternate_queue = [];
|
||||
|
||||
// Private method to check if angularAMD has been initialized
|
||||
function checkBootstrapped() {
|
||||
if ( !bootstrapped ) {
|
||||
throw new Error('angularAMD not initialized. Need to call angularAMD.bootstrap(app) first.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an alternate angular so that subsequent call to angular.module will queue up
|
||||
* the module created for later processing via the .processQueue method.
|
||||
*
|
||||
* This delaying processing is needed as angular does not recognize any newly created
|
||||
* module after angular.bootstrap has ran. The only way to add new objects to angular
|
||||
* post bootstrap is using cached provider.
|
||||
*
|
||||
* Once the modules has been queued, processQueue would then use each module's _invokeQueue
|
||||
* and _runBlock to recreate object using cached $provider. In essence, creating a duplicate
|
||||
* object into the current ng-app. As result, if there are subsequent call to retrieve the
|
||||
* module post processQueue, it would retrieve a module that is not integrated into the ng-app.
|
||||
*
|
||||
* Therefore, any subsequent to call to angular.module after processQueue should return undefined
|
||||
* to prevent obtaining a duplicated object. However, it is critical that angular.module return
|
||||
* appropriate object *during* processQueue.
|
||||
*/
|
||||
function setAlternateAngular() {
|
||||
// This method cannot be called more than once
|
||||
if (alt_angular) {
|
||||
throw new Error('setAlternateAngular can only be called once.');
|
||||
} else {
|
||||
alt_angular = {};
|
||||
}
|
||||
|
||||
// Make sure that bootstrap has been called
|
||||
checkBootstrapped();
|
||||
|
||||
// Create a a copy of orig_angular with on demand loading capability
|
||||
orig_angular.extend(alt_angular, orig_angular);
|
||||
|
||||
// Custom version of angular.module used as cache
|
||||
alt_angular.module = function (name, requires) {
|
||||
if (typeof requires === 'undefined') {
|
||||
// Return module from alternate_modules if it was created using the alt_angular
|
||||
if (alternate_modules_tracker.hasOwnProperty(name)) {
|
||||
return alternate_modules[name];
|
||||
} else {
|
||||
return orig_angular.module(name);
|
||||
}
|
||||
} else {
|
||||
var orig_mod = orig_angular.module.apply(null, arguments),
|
||||
item = { name: name, module: orig_mod};
|
||||
alternate_queue.push(item);
|
||||
orig_angular.extend(orig_mod, onDemandLoader);
|
||||
|
||||
/*
|
||||
Use `alternate_modules_tracker` to track which module has been created by alt_angular
|
||||
but use `alternate_modules` to cache the module created. This is to simplify the
|
||||
removal of cached modules after .processQueue.
|
||||
*/
|
||||
alternate_modules_tracker[name] = true;
|
||||
alternate_modules[name] = orig_mod;
|
||||
|
||||
// Return created module
|
||||
return orig_mod;
|
||||
}
|
||||
};
|
||||
|
||||
window.angular = alt_angular;
|
||||
}
|
||||
|
||||
// Constructor
|
||||
function AngularAMD() {}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to generate angular's $routeProvider.route. 'config' input param must be an object.
|
||||
*
|
||||
* Populate the resolve attribute using either 'controllerUrl' or 'controller'. If 'controllerUrl'
|
||||
* is passed, it will attempt to load the Url using requirejs and remove the attribute from the config
|
||||
* object. Otherwise, it will attempt to populate resolve by loading what's been passed in 'controller'.
|
||||
* If neither is passed, resolve is not populated.
|
||||
*
|
||||
* This function works as a pass-through, meaning what ever is passed in as 'config' will be returned,
|
||||
* except for 'controllerUrl' attribute.
|
||||
*
|
||||
*/
|
||||
AngularAMD.prototype.route = function (config) {
|
||||
// Initialization not necessary to call this method.
|
||||
var load_controller;
|
||||
|
||||
/*
|
||||
If `controllerUrl` is provided, load the provided Url using requirejs. If `controller` is not provided
|
||||
but `controllerUrl` is, assume that module to be loaded will return a function to act as controller.
|
||||
|
||||
Otherwise, attempt to load the controller using the controller name. In the later case, controller name
|
||||
is expected to be defined as one of 'paths' in main.js.
|
||||
*/
|
||||
if ( config.hasOwnProperty('controllerUrl') ) {
|
||||
load_controller = config.controllerUrl;
|
||||
delete config.controllerUrl;
|
||||
if (typeof config.controller === 'undefined') {
|
||||
// Only controllerUrl is defined. Attempt to set the controller to return value of package loaded.
|
||||
config.controller = [
|
||||
'$scope', '__AAMDCtrl', '$injector',
|
||||
function ($scope, __AAMDCtrl, $injector) {
|
||||
if (typeof __AAMDCtrl !== 'undefined' ) {
|
||||
$injector.invoke(__AAMDCtrl, this, { '$scope': $scope });
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
} else if (typeof config.controller === 'string') {
|
||||
load_controller = config.controller;
|
||||
}
|
||||
|
||||
// If controller needs to be loaded, append to the resolve property
|
||||
if (load_controller) {
|
||||
var resolve = config.resolve || {};
|
||||
resolve['__AAMDCtrl'] = ['$q', '$rootScope', function ($q, $rootScope) { // jshint ignore:line
|
||||
var defer = $q.defer();
|
||||
require([load_controller], function (ctrl) {
|
||||
defer.resolve(ctrl);
|
||||
$rootScope.$apply();
|
||||
});
|
||||
return defer.promise;
|
||||
}];
|
||||
config.resolve = resolve;
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Expose name of the app that has been bootstrapped
|
||||
*/
|
||||
AngularAMD.prototype.appname = function () {
|
||||
checkBootstrapped();
|
||||
return app_name;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Recreate the modules created by alternate angular in ng-app using cached $provider.
|
||||
* As AMD loader does not guarantee the order of dependency in a require([...],...)
|
||||
* clause, user must make sure that dependecies are clearly setup in shim in order
|
||||
* for this to work.
|
||||
*
|
||||
* HACK ALERT:
|
||||
* This method relay on inner working of angular.module code, and access _invokeQueue
|
||||
* and _runBlock private variable. Must test carefully with each release of angular.
|
||||
*
|
||||
* As of AngularJS 1.3.x, there is new _configBlocks that get populated with configuration
|
||||
* blocks, thus replacing the need for "provider === '$injector' && method === 'invoke'"
|
||||
* logic.
|
||||
*/
|
||||
AngularAMD.prototype.processQueue = function () {
|
||||
checkBootstrapped();
|
||||
|
||||
if (typeof alt_angular === 'undefined') {
|
||||
throw new Error('Alternate angular not set. Make sure that `enable_ngload` option has been set when calling angularAMD.bootstrap');
|
||||
}
|
||||
|
||||
// Process alternate queue in FIFO fashion
|
||||
function processRunBlock(block) {
|
||||
//console.info('"' + item.name + '": executing run block: ', run_block);
|
||||
run_injector.invoke(block);
|
||||
}
|
||||
|
||||
while (alternate_queue.length) {
|
||||
var item = alternate_queue.shift(),
|
||||
invokeQueue = item.module._invokeQueue,
|
||||
y;
|
||||
|
||||
// Setup the providers define in the module
|
||||
// console.info('invokeQueue: ', invokeQueue);
|
||||
for (y = 0; y < invokeQueue.length; y += 1) {
|
||||
var q = invokeQueue[y],
|
||||
provider = q[0],
|
||||
method = q[1],
|
||||
args = q[2];
|
||||
|
||||
// Make sure that provider exists.
|
||||
if (app_cached_providers.hasOwnProperty(provider)) {
|
||||
var cachedProvider;
|
||||
if (provider === '$injector' && method === 'invoke') {
|
||||
cachedProvider = config_injector;
|
||||
} else {
|
||||
cachedProvider = app_cached_providers[provider];
|
||||
}
|
||||
// console.info('"' + item.name + '": applying ' + provider + '.' + method + ' for args: ', args);
|
||||
cachedProvider[method].apply(null, args);
|
||||
} else {
|
||||
// Make sure that console exists before calling it
|
||||
if ( window.console ) {
|
||||
window.console.error('"' + provider + '" not found!!!');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
As of AngularJS 1.3.x, the config block are now stored in a new _configBlocks private
|
||||
variable. Loop through the list and invoke the config block with config_injector
|
||||
*/
|
||||
if (item.module._configBlocks) {
|
||||
var configBlocks = item.module._configBlocks;
|
||||
|
||||
// console.info('configBlock: ', configBlocks);
|
||||
for (y = 0; y < configBlocks.length; y += 1) {
|
||||
var cf = configBlocks[y],
|
||||
cf_method = cf[1],
|
||||
cf_args = cf[2];
|
||||
|
||||
config_injector[cf_method].apply(null, cf_args);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Execute the run block of the module
|
||||
if (item.module._runBlocks) {
|
||||
angular.forEach(item.module._runBlocks, processRunBlock);
|
||||
}
|
||||
|
||||
/*
|
||||
Clear the cached modules created by alt_angular so that subsequent call to
|
||||
angular.module will return undefined.
|
||||
*/
|
||||
alternate_modules = {};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return cached app provider
|
||||
*/
|
||||
AngularAMD.prototype.getCachedProvider = function (provider_name) {
|
||||
checkBootstrapped();
|
||||
// Hack used for unit testing that orig_angular has been captured
|
||||
var cachedProvider;
|
||||
|
||||
switch(provider_name) {
|
||||
case '__orig_angular':
|
||||
cachedProvider = orig_angular;
|
||||
break;
|
||||
case '__alt_angular':
|
||||
cachedProvider = alt_angular;
|
||||
break;
|
||||
case '__orig_app':
|
||||
cachedProvider = orig_app;
|
||||
break;
|
||||
case '__alt_app':
|
||||
cachedProvider = alt_app;
|
||||
break;
|
||||
default:
|
||||
cachedProvider = app_cached_providers[provider_name];
|
||||
}
|
||||
|
||||
return cachedProvider;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create inject function that uses cached $injector.
|
||||
* Designed primarly to be used during unit testing.
|
||||
*/
|
||||
AngularAMD.prototype.inject = function () {
|
||||
checkBootstrapped();
|
||||
return run_injector.invoke.apply(null, arguments);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create config function that uses cached config_injector.
|
||||
* Designed to simulate app.config.
|
||||
*/
|
||||
AngularAMD.prototype.config = function () {
|
||||
checkBootstrapped();
|
||||
return config_injector.invoke.apply(null, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset angularAMD for resuse
|
||||
*/
|
||||
AngularAMD.prototype.reset = function () {
|
||||
if (typeof orig_angular === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Restore original angular instance
|
||||
window.angular = orig_angular;
|
||||
|
||||
// Clear stored app
|
||||
orig_app = undefined;
|
||||
alt_app = undefined;
|
||||
|
||||
// Clear original angular
|
||||
alt_angular = undefined;
|
||||
orig_angular = undefined;
|
||||
onDemandLoader = {};
|
||||
preBootstrapLoaderQueue = [];
|
||||
|
||||
// Clear private variables
|
||||
alternate_queue = [];
|
||||
app_name = undefined;
|
||||
run_injector = undefined;
|
||||
config_injector = undefined;
|
||||
app_cached_providers = {};
|
||||
|
||||
// Clear bootstrap flag but there is no way to un-bootstrap AngularJS
|
||||
bootstrapped = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialization of angularAMD that bootstraps AngularJS. The objective is to cache the
|
||||
* $provider and $injector from the app to be used later.
|
||||
*
|
||||
* enable_ngload:
|
||||
*/
|
||||
AngularAMD.prototype.bootstrap = function (app, enable_ngload, elem) {
|
||||
// Prevent bootstrap from being called multiple times
|
||||
if (bootstrapped) {
|
||||
throw Error('bootstrap can only be called once.');
|
||||
}
|
||||
|
||||
if (typeof enable_ngload === 'undefined') {
|
||||
enable_ngload = true;
|
||||
}
|
||||
|
||||
// Store reference to original angular and app
|
||||
orig_angular = angular;
|
||||
|
||||
// Create new version of app
|
||||
orig_app = app;
|
||||
alt_app = {};
|
||||
orig_angular.extend(alt_app, orig_app);
|
||||
|
||||
// Determine element to bootstrap angular
|
||||
elem = elem || document.documentElement;
|
||||
|
||||
// Cache provider needed
|
||||
app.config(
|
||||
['$controllerProvider', '$compileProvider', '$filterProvider', '$animateProvider', '$provide', '$injector', function (controllerProvider, compileProvider, filterProvider, animateProvider, provide, injector) {
|
||||
// Cache Providers
|
||||
config_injector = injector;
|
||||
app_cached_providers = {
|
||||
$controllerProvider: controllerProvider,
|
||||
$compileProvider: compileProvider,
|
||||
$filterProvider: filterProvider,
|
||||
$animateProvider: animateProvider,
|
||||
$provide: provide
|
||||
};
|
||||
|
||||
// Substitue provider methods from app call the cached provider
|
||||
angular.extend(onDemandLoader, {
|
||||
provider : function(name, constructor) {
|
||||
provide.provider(name, constructor);
|
||||
return this;
|
||||
},
|
||||
controller : function(name, constructor) {
|
||||
controllerProvider.register(name, constructor);
|
||||
return this;
|
||||
},
|
||||
directive : function(name, constructor) {
|
||||
compileProvider.directive(name, constructor);
|
||||
return this;
|
||||
},
|
||||
filter : function(name, constructor) {
|
||||
filterProvider.register(name, constructor);
|
||||
return this;
|
||||
},
|
||||
factory : function(name, constructor) {
|
||||
// console.log('onDemandLoader.factory called for ' + name);
|
||||
provide.factory(name, constructor);
|
||||
return this;
|
||||
},
|
||||
service : function(name, constructor) {
|
||||
provide.service(name, constructor);
|
||||
return this;
|
||||
},
|
||||
constant : function(name, constructor) {
|
||||
provide.constant(name, constructor);
|
||||
return this;
|
||||
},
|
||||
value : function(name, constructor) {
|
||||
provide.value(name, constructor);
|
||||
return this;
|
||||
},
|
||||
animation: angular.bind(animateProvider, animateProvider.register)
|
||||
});
|
||||
angular.extend(alt_app, onDemandLoader);
|
||||
|
||||
}]
|
||||
);
|
||||
|
||||
// Get the injector for the app
|
||||
app.run(['$injector', function ($injector) {
|
||||
// $injector must be obtained in .run instead of .config
|
||||
run_injector = $injector;
|
||||
app_cached_providers.$injector = run_injector;
|
||||
}]);
|
||||
|
||||
// Store the app name needed by .bootstrap function.
|
||||
app_name = app.name;
|
||||
|
||||
// If there are angular provider recipe queued up, process it
|
||||
if (preBootstrapLoaderQueue.length > 0) {
|
||||
for (var iq = 0; iq < preBootstrapLoaderQueue.length; iq += 1) {
|
||||
var item = preBootstrapLoaderQueue[iq];
|
||||
orig_app[item.recipe](item.name, item.constructor);
|
||||
}
|
||||
preBootstrapLoaderQueue = [];
|
||||
}
|
||||
|
||||
// Create a app.register object to keep backward compatibility
|
||||
orig_app.register = onDemandLoader;
|
||||
|
||||
// Bootstrap Angular
|
||||
orig_angular.element(document).ready(function () {
|
||||
orig_angular.bootstrap(elem, [app_name]);
|
||||
// Indicate bootstrap completed
|
||||
bootstrapped = true;
|
||||
|
||||
// Replace angular.module
|
||||
if (enable_ngload) {
|
||||
//console.info('Setting alternate angular');
|
||||
setAlternateAngular();
|
||||
}
|
||||
});
|
||||
|
||||
// Return app
|
||||
return alt_app;
|
||||
};
|
||||
|
||||
// Define provider
|
||||
function executeProvider(providerRecipe) {
|
||||
return function (name, constructor) {
|
||||
if (bootstrapped) {
|
||||
onDemandLoader[providerRecipe](name, constructor);
|
||||
} else {
|
||||
// Queue up the request to be used during .bootstrap
|
||||
preBootstrapLoaderQueue.push({
|
||||
'recipe': providerRecipe,
|
||||
'name': name,
|
||||
'constructor': constructor
|
||||
});
|
||||
}
|
||||
return this;
|
||||
};
|
||||
}
|
||||
|
||||
// .provider
|
||||
AngularAMD.prototype.provider = executeProvider('provider');
|
||||
// .controller
|
||||
AngularAMD.prototype.controller = executeProvider('controller');
|
||||
// .directive
|
||||
AngularAMD.prototype.directive = executeProvider('directive');
|
||||
// .filter
|
||||
AngularAMD.prototype.filter = executeProvider('filter');
|
||||
// .factory
|
||||
AngularAMD.prototype.factory = executeProvider('factory');
|
||||
// .service
|
||||
AngularAMD.prototype.service = executeProvider('service');
|
||||
// .constant
|
||||
AngularAMD.prototype.constant = executeProvider('constant');
|
||||
// .value
|
||||
AngularAMD.prototype.value = executeProvider('value');
|
||||
// .animation
|
||||
AngularAMD.prototype.animation = executeProvider('animation');
|
||||
|
||||
// Create a new instance and return
|
||||
return new AngularAMD();
|
||||
|
||||
});
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
16
src/main/webapp/services/services.js
Normal file
16
src/main/webapp/services/services.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
var Owner = ['$resource', function($resource) {
|
||||
return $resource('/petclinic/api/owners/:id');
|
||||
}];
|
||||
|
||||
var Pet = ['$resource', function($resource) {
|
||||
return $resource('/petclinic/api/owners/:ownerId/pets', {ownerId : '@ownerId'});
|
||||
}];
|
||||
|
||||
var Vet = ['$resource', function($resource) {
|
||||
return $resource('/petclinic/api/vets/:vetId');
|
||||
}];
|
||||
|
||||
var Visit = ['$resource', function($resource) {
|
||||
return $resource('/petclinic/api/pets/:petId/visits', {petId : '@id'});
|
||||
}];
|
||||
|
Loading…
Reference in a new issue