diff --git a/.gitignore b/.gitignore index c278227794..db18feec03 100644 --- a/.gitignore +++ b/.gitignore @@ -25,11 +25,11 @@ _NCrunch_*/ umbraco.config *.vs10x App_Data/TEMP/* -umbraco/presentation/umbraco/plugins/* -umbraco/presentation/usercontrols/* -umbraco/presentation/scripts/* -umbraco/presentation/fonts/* -umbraco/presentation/css/* +[Uu]mbraco/[Pp]resentation/[Uu]mbraco/[Pp]lugins/* +[Uu]mbraco/[Pp]resentation/[Uu]ser[Cc]ontrols/* +[Uu]mbraco/[Pp]resentation/[Ss]cripts/* +[Uu]mbraco/[Pp]resentation/[Ff]onts/* +[Uu]mbraco/[Pp]resentation/[Cc]ss/* src/Umbraco.Web.UI/[Cc]ss/* src/Umbraco.Web.UI/App_Code/* @@ -46,7 +46,6 @@ src/Umbraco.Web.UI/Web.*.config.transformed umbraco/presentation/umbraco/plugins/uComponents/uComponentsInstaller.ascx umbraco/presentation/packages/uComponents/MultiNodePicker/CustomTreeService.asmx _BuildOutput/* -*.ncrunchsolution build/UmbracoCms.AllBinaries*zip build/UmbracoCms.WebPI*zip build/UmbracoCms*zip @@ -56,35 +55,33 @@ src/Umbraco.Tests/config/trees.config src/Umbraco.Web.UI/web.config *.orig src/Umbraco.Tests/config/404handlers.config -src/Umbraco.Web.UI/Views/*.cshtml -src/Umbraco.Web.UI/Views/*.vbhtml -src/Umbraco.Tests/config/umbracoSettings.config -src/Umbraco.Web.UI/Views/* +src/Umbraco.Web.UI/[Vv]iews/*.cshtml +src/Umbraco.Web.UI/[Vv]iews/*.vbhtml +src/Umbraco.Tests/[Cc]onfig/umbracoSettings.config +src/Umbraco.Web.UI/[Vv]iews/* src/packages/ src/packages/repositories.config -src/Umbraco.Web.UI/[W]eb.config +src/Umbraco.Web.UI/[Ww]eb.config *.transformed webpihash.txt node_modules -src/Umbraco.Web.UI/umbraco/lib/* -src/Umbraco.Web.UI/umbraco/js/umbraco.* -src/Umbraco.Web.UI/umbraco/js/routes.js -src/Umbraco.Web.UI/umbraco/js/main.js -src/Umbraco.Web.UI/umbraco/js/app.js -src/Umbraco.Web.UI/umbraco/[V]iews/ -src/Umbraco.Web.UI/umbraco/[V]iews/**/*.js -src/Umbraco.Web.UI/umbraco/[V]iews/**/*.css -src/Umbraco.Web.UI/umbraco/[V]iews/**/*.html -src/Umbraco.Web.UI/umbraco/assets/ - -src/Umbraco.Web.UI.Client/build/* -src/Umbraco.Web.UI.Client/build/**/*.* -src/Umbraco.Web.UI.Client/build/belle/ - -src/Umbraco.Web.UI/UserControls/ +src/Umbraco.Web.UI/[Uu]mbraco/[Ll]ib/* +src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/umbraco.* +src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/routes.js +src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/main.js +src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/app.js +src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/ +src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.js +src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.css +src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.html +src/Umbraco.Web.UI/[Uu]mbraco/[Aa]ssets/* +src/Umbraco.Web.UI.Client/[Bb]uild/* +src/Umbraco.Web.UI.Client/[Bb]uild/[Bb]elle/ +src/Umbraco.Web.UI/[Uu]ser[Cc]ontrols/ build/_BuildOutput/ -build/belle/ +src/Umbraco.Web.UI.Client/src/[Ll]ess/*.css + diff --git a/src/Umbraco.Core/CoreBootManager.cs b/src/Umbraco.Core/CoreBootManager.cs index 091f07bd19..0419fb0cd0 100644 --- a/src/Umbraco.Core/CoreBootManager.cs +++ b/src/Umbraco.Core/CoreBootManager.cs @@ -75,6 +75,8 @@ namespace Umbraco.Core //initialize the DatabaseContext dbContext.Initialize(); + InitializeModelMappers(); + //now we need to call the initialize methods ApplicationEventsResolver.Current.ApplicationEventHandlers .ForEach(x => x.OnApplicationInitialized(UmbracoApplication, ApplicationContext)); @@ -95,6 +97,14 @@ namespace Umbraco.Core ApplicationContext = ApplicationContext.Current = new ApplicationContext(dbContext, serviceContext); } + /// + /// This method allows for configuration of model mappers + /// + protected virtual void InitializeModelMappers() + { + //TODO: There will most likely be AutoMapper configs to put in here, we know they exist in web for now so we'll leave this here for future use + } + /// /// Special method to initialize the ProfilerResolver /// diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs index 34be23e1f1..bc860705a2 100644 --- a/src/Umbraco.Core/IO/IOHelper.cs +++ b/src/Umbraco.Core/IO/IOHelper.cs @@ -249,6 +249,32 @@ namespace Umbraco.Core.IO return _rootDir; } + internal static string GetRootDirectoryBinFolder() + { + string binFolder = string.Empty; + if (string.IsNullOrEmpty(_rootDir)) + { + binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory.FullName; + return binFolder; + } + + binFolder = Path.Combine(GetRootDirectorySafe(), "bin"); + +#if DEBUG + var debugFolder = Path.Combine(binFolder, "debug"); + if (Directory.Exists(debugFolder)) + return debugFolder; +#endif + var releaseFolder = Path.Combine(binFolder, "release"); + if (Directory.Exists(releaseFolder)) + return releaseFolder; + + if (Directory.Exists(binFolder)) + return binFolder; + + return _rootDir; + } + /// /// Allows you to overwrite RootDirectory, which would otherwise be resolved /// automatically upon application start. diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs index 7fa04e6e58..e4299bbced 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs @@ -321,7 +321,7 @@ namespace Umbraco.Core.Persistence.Repositories sql.Select("*") .From() .LeftJoin() - .On(left => left.Id, right => right.NodeId) + .On(left => left.AllowedId, right => right.NodeId) .Where(x => x.Id == id); var allowedContentTypeDtos = Database.Fetch(sql); diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserRepository.cs index 077456da1b..93719e29e3 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserRepository.cs @@ -5,5 +5,8 @@ namespace Umbraco.Core.Persistence.Repositories internal interface IUserRepository : IRepositoryQueryable { IProfile GetProfileById(int id); + IProfile GetProfileByUserName(string username); + IUser GetUserByUserName(string username); + IUser GetUserById(int id); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs b/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs index d88a00f187..c8c5d3e1d9 100644 --- a/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs @@ -147,6 +147,63 @@ namespace Umbraco.Core.Persistence.Repositories return new Profile(dto.Id, dto.UserName); } + public IProfile GetProfileByUserName(string username) + { + var sql = GetBaseQuery(false); + sql.Where("umbracoUser.userLogin = @Username", new { Username = username }); + + var dto = Database.FirstOrDefault(sql); + + if (dto == null) + return null; + + return new Profile(dto.Id, dto.UserName); + } + + public IUser GetUserByUserName(string username) + { + var sql = GetBaseQuery(false); + sql.Where("umbracoUser.userLogin = @Username", new { Username = username }); + + var dto = Database.FirstOrDefault(sql); + + if (dto == null) + return null; + + return new User(_userTypeRepository.Get(dto.Type)) + { + Id = dto.Id, + Email = dto.Email, + Language = dto.UserLanguage, + Name = dto.UserName, + NoConsole = dto.NoConsole, + IsLockedOut = dto.Disabled + }; + + } + + public IUser GetUserById(int id) + { + var sql = GetBaseQuery(false); + sql.Where(GetBaseWhereClause(), new { Id = id }); + + var dto = Database.FirstOrDefault(sql); + + if (dto == null) + return null; + + return new User(_userTypeRepository.Get(dto.Type)) + { + Id = dto.Id, + Email = dto.Email, + Language = dto.UserLanguage, + Name = dto.UserName, + NoConsole = dto.NoConsole, + IsLockedOut = dto.Disabled + }; + + } + #endregion } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/IUserService.cs b/src/Umbraco.Core/Services/IUserService.cs index a6b3f8ceef..678fbf9292 100644 --- a/src/Umbraco.Core/Services/IUserService.cs +++ b/src/Umbraco.Core/Services/IUserService.cs @@ -15,6 +15,10 @@ namespace Umbraco.Core.Services /// IProfile GetProfileById(int id); + IProfile GetProfileByUserName(string username); + IUser GetUserByUserName(string username); + IUser GetUserById(int id); + /// /// Gets an IUserType by its Alias /// diff --git a/src/Umbraco.Core/Services/UserService.cs b/src/Umbraco.Core/Services/UserService.cs index a0b226bfad..b86ad2b2d8 100644 --- a/src/Umbraco.Core/Services/UserService.cs +++ b/src/Umbraco.Core/Services/UserService.cs @@ -44,6 +44,31 @@ namespace Umbraco.Core.Services } } + public IProfile GetProfileByUserName(string username) + { + using (var repository = _repositoryFactory.CreateUserRepository(_uowProvider.GetUnitOfWork())) + { + return repository.GetProfileByUserName(username); + } + } + + public IUser GetUserByUserName(string username) + { + using (var repository = _repositoryFactory.CreateUserRepository(_uowProvider.GetUnitOfWork())) + { + return repository.GetUserByUserName(username); + } + } + + public IUser GetUserById(int id) + { + using (var repository = _repositoryFactory.CreateUserRepository(_uowProvider.GetUnitOfWork())) + { + return repository.GetUserById(id); + } + } + + /// /// Gets an IUserType by its Alias /// diff --git a/src/Umbraco.Core/Standalone/ServiceContextManager.cs b/src/Umbraco.Core/Standalone/ServiceContextManager.cs index 29a2945edd..ea9464242b 100644 --- a/src/Umbraco.Core/Standalone/ServiceContextManager.cs +++ b/src/Umbraco.Core/Standalone/ServiceContextManager.cs @@ -1,4 +1,6 @@ using System; +using System.Diagnostics; +using System.Reflection; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.UnitOfWork; @@ -14,12 +16,18 @@ namespace Umbraco.Core.Standalone private ServiceContext _serviceContext; private readonly StandaloneCoreApplication _application; - public ServiceContextManager(string connectionString, string providerName) + public ServiceContextManager(string connectionString, string providerName, string baseDirectory) { _connectionString = connectionString; _providerName = providerName; - _application = StandaloneCoreApplication.GetApplication(); + Trace.WriteLine("ServiceContextManager-Current AppDomain: " + AppDomain.CurrentDomain.FriendlyName); + Trace.WriteLine("ServiceContextManager-Current AppDomain: " + AppDomain.CurrentDomain.BaseDirectory); + + var examineEventHandlerToRemove = Type.GetType("Umbraco.Web.Search.ExamineEvents, Umbraco.Web"); + + _application = StandaloneCoreApplication.GetApplication(baseDirectory); + _application.WithoutApplicationEventHandler(examineEventHandlerToRemove); _application.Start(); } diff --git a/src/Umbraco.Core/Standalone/StandaloneCoreApplication.cs b/src/Umbraco.Core/Standalone/StandaloneCoreApplication.cs index 0e0081d948..c22a648478 100644 --- a/src/Umbraco.Core/Standalone/StandaloneCoreApplication.cs +++ b/src/Umbraco.Core/Standalone/StandaloneCoreApplication.cs @@ -8,7 +8,10 @@ namespace Umbraco.Core.Standalone /// /// Initializes a new instance of the class. /// - protected StandaloneCoreApplication() { } + protected StandaloneCoreApplication(string baseDirectory) + { + _baseDirectory = baseDirectory; + } /// /// Provides the application boot manager. @@ -16,11 +19,12 @@ namespace Umbraco.Core.Standalone /// An application boot manager. protected override IBootManager GetBootManager() { - return new StandaloneCoreBootManager(this, _handlersToAdd, _handlersToRemove); + return new StandaloneCoreBootManager(this, _handlersToAdd, _handlersToRemove, _baseDirectory); } #region Application + private readonly string _baseDirectory; private static StandaloneCoreApplication _application; private static bool _started; private static readonly object AppLock = new object(); @@ -28,11 +32,11 @@ namespace Umbraco.Core.Standalone /// /// Gets the instance of the standalone Umbraco application. /// - public static StandaloneCoreApplication GetApplication() + public static StandaloneCoreApplication GetApplication(string baseDirectory) { lock (AppLock) { - return _application ?? (_application = new StandaloneCoreApplication()); + return _application ?? (_application = new StandaloneCoreApplication(baseDirectory)); } } diff --git a/src/Umbraco.Core/Standalone/StandaloneCoreBootManager.cs b/src/Umbraco.Core/Standalone/StandaloneCoreBootManager.cs index 46871e2055..84c73f95b7 100644 --- a/src/Umbraco.Core/Standalone/StandaloneCoreBootManager.cs +++ b/src/Umbraco.Core/Standalone/StandaloneCoreBootManager.cs @@ -10,12 +10,16 @@ namespace Umbraco.Core.Standalone { private readonly IEnumerable _handlersToAdd; private readonly IEnumerable _handlersToRemove; + private readonly string _baseDirectory; - public StandaloneCoreBootManager(UmbracoApplicationBase umbracoApplication, IEnumerable handlersToAdd, IEnumerable handlersToRemove) + public StandaloneCoreBootManager(UmbracoApplicationBase umbracoApplication, IEnumerable handlersToAdd, IEnumerable handlersToRemove, string baseDirectory) : base(umbracoApplication) { _handlersToAdd = handlersToAdd; _handlersToRemove = handlersToRemove; + _baseDirectory = baseDirectory; + + base.InitializeApplicationRootPath(_baseDirectory); // this is only here to ensure references to the assemblies needed for // the DataTypesResolver otherwise they won't be loaded into the AppDomain. @@ -25,8 +29,10 @@ namespace Umbraco.Core.Standalone protected override void InitializeApplicationEventsResolver() { base.InitializeApplicationEventsResolver(); + foreach (var type in _handlersToAdd) ApplicationEventsResolver.Current.AddType(type); + foreach (var type in _handlersToRemove) ApplicationEventsResolver.Current.RemoveType(type); } @@ -36,7 +42,7 @@ namespace Umbraco.Core.Standalone base.InitializeResolvers(); //Mappers are not resolved, which could be because of a known TypeMapper issue - MappingResolver.Reset(); + /*MappingResolver.Reset(); MappingResolver.Current = new MappingResolver( () => new List @@ -47,7 +53,7 @@ namespace Umbraco.Core.Standalone typeof (MediaTypeMapper), typeof (DataTypeDefinitionMapper), typeof (UmbracoEntityMapper) - }); + });*/ } } } \ No newline at end of file diff --git a/src/Umbraco.Core/TypeFinder.cs b/src/Umbraco.Core/TypeFinder.cs index f3345ca01b..f74d7099d1 100644 --- a/src/Umbraco.Core/TypeFinder.cs +++ b/src/Umbraco.Core/TypeFinder.cs @@ -73,8 +73,10 @@ namespace Umbraco.Core { //NOTE: we cannot use AppDomain.CurrentDomain.GetAssemblies() because this only returns assemblies that have // already been loaded in to the app domain, instead we will look directly into the bin folder and load each one. - var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory; - var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList(); + var binFolder = IOHelper.GetRootDirectoryBinFolder(); + var binAssemblyFiles = Directory.GetFiles(binFolder, "*.dll", SearchOption.TopDirectoryOnly).ToList(); + //var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory; + //var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList(); assemblies = new List(); foreach (var a in binAssemblyFiles) { diff --git a/src/Umbraco.Tests/App.config b/src/Umbraco.Tests/App.config index b4fa2f7a10..cfbefb6754 100644 --- a/src/Umbraco.Tests/App.config +++ b/src/Umbraco.Tests/App.config @@ -22,7 +22,6 @@ - diff --git a/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs b/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs index 958e858c79..9c0dcff245 100644 --- a/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs +++ b/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs @@ -36,7 +36,7 @@ namespace Umbraco.Tests.Models.Mapping var contentType = MockedContentTypes.CreateSimpleContentType(); var content = MockedContent.CreateSimpleContent(contentType); - var mapper = new ContentModelMapper(ApplicationContext, new ProfileModelMapper()); + var mapper = new ContentModelMapper(ApplicationContext, new UserModelMapper()); var result = mapper.ToContentItemDisplay(content); @@ -73,7 +73,7 @@ namespace Umbraco.Tests.Models.Mapping //ensure that nothing is marked as dirty content.ResetDirtyProperties(false); - var mapper = new ContentModelMapper(ApplicationContext, new ProfileModelMapper()); + var mapper = new ContentModelMapper(ApplicationContext, new UserModelMapper()); var result = mapper.ToContentItemDisplay(content); diff --git a/src/Umbraco.Web.UI.Client/README.md b/src/Umbraco.Web.UI.Client/README.md new file mode 100644 index 0000000000..81898d5a1c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/README.md @@ -0,0 +1,110 @@ +#Belle + +Umbraco 7 UI, codename "Belle" Built on AngularJS, RequireJS and Twitter Bootstrap + +##Introduction +Slides from the initial demonstration of Belle done at the Umbraco DK Fest can be found here: + +http://rawgithub.com/umbraco/Belle/master/Presentation/index.html + + +##Running the prebuilt site + +###Windows +Right-click the `/build` folder and choose "open in webmatrix", run the website in webmatrix and browse to `localhost:xxxx/Belle/`, this should display the Belle login screen + +###OSX +Open a terminal inside the "/build" folder and run the command: + + python -m SimpleHTTPServer 8080 + +This will start a local webserver, hosting the site on `localhost:8080` browse to localhost:8080/Belle/ which should display the belle login screen. + +##Uing the dev environment +_The dev environment is tad more tricky to get running, since it depends on a number of unit tests and automated tools, to produce the contents of the /build folder_ + +_The dev environment is cross platform, so will work on both osx and windows, and do not currently have any dependencies to .net_ + +###Install node.js +We need node to run tests and automated less compiling and other automated tasks. go to http://nodejs.org. Node.js is a powerfull javascript engine, which allows us to run all our tests and tasks written in javascript locally. + +*note:* On windows you might need to restart explorer.exe to register node. + + +###Install dependencies +Next we need to install all the required packages. This is done with the package tool, included with node.js, open /Umbraco.Belle.Client in cmd.exe or osx terminal and run the command: + + npm install + +this will fetch all needed packages to your local machine. + + +###Install grunt globally +Grunt is a task runner for node.js, and we use it for all automated tasks in the build process. For convenience we need to install it globally on your machine, so it can be used directly in cmd.exe or the terminal. + +So run the command: + + npm install grunt-cli -g + +*note:* On windows you might need to restart explorer.exe to register the grunt cmd. + +*note:* On OSX you might need to run: + + sudo npm install grunt-cli -g + +Now that you have node and grunt installed, you can open `/Umbraco.Belle.Client` in either `cmd.exe` or terminal and run: + + grunt + +This will build the site, merge less files, run tests and create the /Build folder. + +###Automated builds and tests +If you prefer to do test-driven developement, or just dont want to manually run `grunt` on every change, you can simply tell grunt to watch for any changes made in the project, by running: + + grunt watch + + +##Limitations +The current prototype simply uses in-memory storage, so no database dependencies. It is aimed at showing UI, not a complete functional client-server setup. + + +##Project Structure + +All project files are located in /umbraco.belle.client/src which only contains client-side files, everything +related to asp.net are in umbraco.bell + +after building Belle files are located in /build/belle, with all files following AngularJs +conventions: + +###Folders +- */belle/lib:* Dependencies +- */belle/js:* Application javascript files +- */belle/views/common/:* Main application views +- */belle/views/[sectioname]/pagename Editors html +- */belle/views/propertyeditors:* Property Editors html + + +###Files +- */belle/js/app.js:* Main umbraco application / modules +- */belle/js/main.js:* require.js configuration for dependencies +- */belle/js/routes.js:* Application routes +- */belle/js/umbraco.controllers.js:* Application controllers +- */belle/js/umbraco.services.js:* Application services +- */belle/js/umbraco.directives.js:* Application directives +- */belle/js/umbraco.resources.js:* Application resources, like content, media, users, members etc + + +##Getting started +The current app is built, following conventions from angularJs and bootstrap. To get started with the applicaton you will need to atleast know the basics of these frameworks + +###AngularJS +- Excellent introduction videos on http://www.egghead.io/ +- Official guide at: http://docs.angularjs.org/guide/ + +###Require.js +- Introduction: http://javascriptplayground.com/blog/2012/07/requirejs-amd-tutorial-introduction +- Require.js website: http://requirejs.org/ + + + + diff --git a/src/Umbraco.Web.UI.Client/lib/angular/angular.min.js b/src/Umbraco.Web.UI.Client/lib/angular/angular.min.js index 486d5e1c87..ac033dc89b 100644 --- a/src/Umbraco.Web.UI.Client/lib/angular/angular.min.js +++ b/src/Umbraco.Web.UI.Client/lib/angular/angular.min.js @@ -1,173 +1,178 @@ /* - AngularJS v1.1.4 + AngularJS v1.1.5 (c) 2010-2012 Google, Inc. http://angularjs.org License: MIT */ -(function(M,V,s){'use strict';function gc(){var b=M.angular;M.angular=hc;return b}function o(b,a,c){var d;if(b)if(I(b))for(d in b)d!="prototype"&&d!="length"&&d!="name"&&b.hasOwnProperty(d)&&a.call(c,b[d],d);else if(b.forEach&&b.forEach!==o)b.forEach(a,c);else if(!b||typeof b.length!=="number"?0:typeof b.hasOwnProperty!="function"&&typeof b.constructor!="function"||b instanceof P||ca&&b instanceof ca||Da.call(b)!=="[object Object]"||typeof b.callee==="function")for(d=0;d=0&&b.splice(c,1);return a}function W(b,a){if(ra(b)||b&&b.$evalAsync&&b.$watch)throw Error("Can't copy Window or Scope");if(a){if(b===a)throw Error("Can't copy equivalent objects or arrays");if(C(b))for(var c=a.length=0;c2?ka.call(arguments,2):[];return I(a)&&!(a instanceof RegExp)?c.length?function(){return arguments.length?a.apply(b,c.concat(ka.call(arguments,0))):a.apply(b,c)}:function(){return arguments.length?a.apply(b,arguments):a.call(b)}:a}function lc(b,a){var c=a;/^\$+/.test(b)?c=s:ra(a)?c="$WINDOW":a&&V===a?c="$DOCUMENT":a&&a.$evalAsync&&a.$watch&&(c="$SCOPE");return c}function da(b,a){return JSON.stringify(b,lc,a?" ":null)}function tb(b){return x(b)? -JSON.parse(b):b}function Ha(b){b&&b.length!==0?(b=J(""+b),b=!(b=="f"||b=="0"||b=="false"||b=="no"||b=="n"||b=="[]")):b=!1;return b}function ta(b){b=v(b).clone();try{b.html("")}catch(a){}var c=v("
").append(b).html();try{return b[0].nodeType===3?J(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+J(b)})}catch(d){return J(c)}}function bb(b){var a={},c,d;o((b||"").split("&"),function(b){b&&(c=b.split("="),d=decodeURIComponent(c[0]),a[d]=w(c[1])?decodeURIComponent(c[1]):!0)}); -return a}function ub(b){var a=[];o(b,function(b,d){a.push(ua(d,!0)+(b===!0?"":"="+ua(b,!0)))});return a.length?a.join("&"):""}function cb(b){return ua(b,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function ua(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,a?"%20":"+")}function mc(b,a){function c(a){a&&d.push(a)}var d=[b],e,f,i=["ng:app","ng-app","x-ng-app","data-ng-app"],h=/\sng[:\-]app(:\s*([\w\d_]+);?)?\s/; -o(i,function(a){i[a]=!0;c(V.getElementById(a));a=a.replace(":","\\:");b.querySelectorAll&&(o(b.querySelectorAll("."+a),c),o(b.querySelectorAll("."+a+"\\:"),c),o(b.querySelectorAll("["+a+"]"),c))});o(d,function(a){if(!e){var b=h.exec(" "+a.className+" ");b?(e=a,f=(b[2]||"").replace(/\s+/g,",")):o(a.attributes,function(b){if(!e&&i[b.name])e=a,f=b.value})}});e&&a(e,f?[f]:[])}function vb(b,a){var c=function(){b=v(b);a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);a.unshift("ng"); -var c=wb(a);c.invoke(["$rootScope","$rootElement","$compile","$injector",function(a,b,c,d){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return c},d=/^NG_DEFER_BOOTSTRAP!/;if(M&&!d.test(M.name))return c();M.name=M.name.replace(d,"");Ia.resumeBootstrap=function(b){o(b,function(b){a.push(b)});c()}}function db(b,a){a=a||"_";return b.replace(nc,function(b,d){return(d?a:"")+b.toLowerCase()})}function eb(b,a,c){if(!b)throw Error("Argument '"+(a||"?")+"' is "+(c||"required"));return b}function va(b, -a,c){c&&C(b)&&(b=b[b.length-1]);eb(I(b),a,"not a function, got "+(b&&typeof b=="object"?b.constructor.name||"Object":typeof b));return b}function oc(b){function a(a,b,e){return a[b]||(a[b]=e())}return a(a(b,"angular",Object),"module",function(){var b={};return function(d,e,f){e&&b.hasOwnProperty(d)&&(b[d]=null);return a(b,d,function(){function a(c,d,e){return function(){b[e||"push"]([c,d,arguments]);return m}}if(!e)throw Error("No module: "+d);var b=[],c=[],g=a("$injector","invoke"),m={_invokeQueue:b, -_runBlocks:c,requires:e,name:d,provider:a("$provide","provider"),factory:a("$provide","factory"),service:a("$provide","service"),value:a("$provide","value"),constant:a("$provide","constant","unshift"),animation:a("$animationProvider","register"),filter:a("$filterProvider","register"),controller:a("$controllerProvider","register"),directive:a("$compileProvider","directive"),config:g,run:function(a){c.push(a);return this}};f&&g(f);return m})}})}function Ja(b){return b.replace(pc,function(a,b,d,e){return e? -d.toUpperCase():d}).replace(qc,"Moz$1")}function fb(b,a){function c(){var e;for(var b=[this],c=a,i,h,j,g,m,k;b.length;){i=b.shift();h=0;for(j=i.length;h 
"+b;a.removeChild(a.firstChild);gb(this,a.childNodes);this.remove()}else gb(this,b)}function hb(b){return b.cloneNode(!0)}function wa(b){xb(b);for(var a=0,b=b.childNodes||[];a-1}function Ab(b,a){a&&o(a.split(" "),function(a){b.className=S((" "+b.className+" ").replace(/[\n\t]/g," ").replace(" "+S(a)+" "," "))})}function Bb(b, -a){a&&o(a.split(" "),function(a){if(!Ma(b,a))b.className=S(b.className+" "+S(a))})}function gb(b,a){if(a)for(var a=!a.nodeName&&w(a.length)&&!ra(a)?a:[a],c=0;c4096&&c.warn("Cookie '"+a+"' possibly not set or overflowed because it was too large ("+d+" > 4096 bytes)!")}else{if(j.cookie!==H){H=j.cookie;d=H.split("; ");A={};for(g=0;g0&&(A[unescape(e.substring(0,h))]=unescape(e.substring(h+1)))}return A}};h.defer=function(a,b){var c;n++;c=k(function(){delete q[c];e(a)},b||0);q[c]=!0;return c};h.defer.cancel=function(a){return q[a]?(delete q[a],l(a),e(t),!0):!1}}function zc(){this.$get=["$window","$log","$sniffer","$document",function(b,a,c,d){return new yc(b,d,a,c)}]}function Ac(){this.$get=function(){function b(b,d){function e(a){if(a!=k){if(l){if(l==a)l=a.n}else l=a;f(a.n,a.p);f(a,k);k=a;k.n=null}}function f(a, -b){if(a!=b){if(a)a.p=b;if(b)b.n=a}}if(b in a)throw Error("cacheId "+b+" taken");var i=0,h=y({},d,{id:b}),j={},g=d&&d.capacity||Number.MAX_VALUE,m={},k=null,l=null;return a[b]={put:function(a,b){var c=m[a]||(m[a]={key:a});e(c);if(!u(b))return a in j||i++,j[a]=b,i>g&&this.remove(l.key),b},get:function(a){var b=m[a];if(b)return e(b),j[a]},remove:function(a){var b=m[a];if(b){if(b==k)k=b.p;if(b==l)l=b.n;f(b.n,b.p);delete m[a];delete j[a];i--}},removeAll:function(){j={};i=0;m={};k=l=null},destroy:function(){m= -h=j=null;delete a[b]},info:function(){return y({},h,{size:i})}}}var a={};b.info=function(){var b={};o(a,function(a,e){b[e]=a.info()});return b};b.get=function(b){return a[b]};return b}}function Bc(){this.$get=["$cacheFactory",function(b){return b("templates")}]}function Hb(b){var a={},c="Directive",d=/^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,e=/(([\d\w\-_]+)(?:\:([^;]+))?;?)/,f="Template must have exactly one root element. was: ",i=/^\s*(https?|ftp|mailto|file):/;this.directive=function j(d,e){x(d)? -(eb(e,"directive"),a.hasOwnProperty(d)||(a[d]=[],b.factory(d+c,["$injector","$exceptionHandler",function(b,c){var e=[];o(a[d],function(a){try{var f=b.invoke(a);if(I(f))f={compile:Q(f)};else if(!f.compile&&f.link)f.compile=Q(f.link);f.priority=f.priority||0;f.name=f.name||d;f.require=f.require||f.controller&&f.name;f.restrict=f.restrict||"A";e.push(f)}catch(j){c(j)}});return e}])),a[d].push(e)):o(d,sb(j));return this};this.urlSanitizationWhitelist=function(a){return w(a)?(i=a,this):i};this.$get=["$injector", -"$interpolate","$exceptionHandler","$http","$templateCache","$parse","$controller","$rootScope","$document",function(b,g,m,k,l,q,n,B,r){function p(a,b,c){a instanceof v||(a=v(a));o(a,function(b,c){b.nodeType==3&&b.nodeValue.match(/\S+/)&&(a[c]=v(b).wrap("").parent()[0])});var d=D(a,b,a,c);return function(b,c){eb(b,"scope");for(var e=c?za.clone.call(a):a,g=0,f=e.length;gz.priority)break;if(y=z.scope)ea("isolated scope",ba,z,A),L(y)&&(E(A,"ng-isolate-scope"),ba=z),E(A, -"ng-scope"),D=D||z;T=z.name;if(y=z.controller)ha=ha||{},ea("'"+T+"' controller",ha[T],z,A),ha[T]=z;if(y=z.transclude)ea("transclusion",ga,z,A),ga=z,k=z.priority,y=="element"?(R=v(b),A=c.$$element=v(V.createComment(" "+T+": "+c[T]+" ")),b=A[0],fa(e,v(R[0]),b),ia=p(R,d,k)):(R=v(hb(b)).contents(),A.html(""),ia=p(R,d));if(z.template)if(ea("template",N,z,A),N=z,y=I(z.template)?z.template(A,c):z.template,y=Jb(y),z.replace){R=v("
"+S(y)+"
").contents();b=R[0];if(R.length!=1||b.nodeType!==1)throw Error(f+ -y);fa(e,A,b);T={$attr:{}};a=a.concat(G(b,a.splice(w+1,a.length-(w+1)),T));H(c,T);u=a.length}else A.html(y);if(z.templateUrl)ea("template",N,z,A),N=z,l=F(a.splice(w,a.length-w),l,A,c,e,z.replace,ia),u=a.length;else if(z.compile)try{t=z.compile(A,c,ia),I(t)?j(null,t):t&&j(t.pre,t.post)}catch(J){m(J,ta(A))}if(z.terminal)l.terminal=!0,k=Math.max(k,z.priority)}l.scope=D&&D.scope;l.transclude=ga&&ia;return l}function A(d,e,g,f){var l=!1;if(a.hasOwnProperty(e))for(var i,e=b.get(e+c),n=0,k=e.length;ni.priority)&&i.restrict.indexOf(g)!=-1)d.push(i),l=!0}catch(q){m(q)}return l}function H(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;o(a,function(d,e){e.charAt(0)!="$"&&(b[e]&&(d+=(e==="style"?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});o(b,function(b,g){g=="class"?(E(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):g=="style"?e.attr("style",e.attr("style")+";"+b):g.charAt(0)!="$"&&!a.hasOwnProperty(g)&&(a[g]=b,d[g]=c[g])})}function F(a,b,c,d,e,g,j){var i=[],n,m,q=c[0],p=a.shift(),ya=y({}, -p,{controller:null,templateUrl:null,transclude:null,scope:null}),p=I(p.templateUrl)?p.templateUrl(c,d):p.templateUrl;c.html("");k.get(p,{cache:l}).success(function(l){var k,p,l=Jb(l);if(g){p=v("
"+S(l)+"
").contents();k=p[0];if(p.length!=1||k.nodeType!==1)throw Error(f+l);l={$attr:{}};fa(e,c,k);G(k,a,l);H(d,l)}else k=q,c.html(l);a.unshift(ya);n=R(a,k,d,j);for(m=D(c[0].childNodes,j);i.length;){var B=i.shift(),l=i.shift();p=i.shift();var r=i.shift(),F=k;l!==q&&(F=hb(k),fa(p,v(l),F));n(function(){b(m, -B,F,e,r)},B,F,e,r)}i=null}).error(function(a,b,c,d){throw Error("Failed to load template: "+d.url);});return function(a,c,d,e,g){i?(i.push(c),i.push(d),i.push(e),i.push(g)):n(function(){b(m,c,d,e,g)},c,d,e,g)}}function N(a,b){return b.priority-a.priority}function ea(a,b,c,d){if(b)throw Error("Multiple directives ["+b.name+", "+c.name+"] asking for "+a+" on: "+ta(d));}function ga(a,b){var c=g(b,!0);c&&a.push({priority:0,compile:Q(function(a,b){var d=b.parent(),e=d.data("$binding")||[];e.push(c);E(d.data("$binding", -e),"ng-binding");a.$watch(c,function(a){b[0].nodeValue=a})})})}function z(a,b,c,d){var e=g(c,!0);e&&b.push({priority:100,compile:Q(function(a,b,c){b=c.$$observers||(c.$$observers={});if(e=g(c[d],!0))c[d]=e(a),(b[d]||(b[d]=[])).$$inter=!0,(c.$$observers&&c.$$observers[d].$$scope||a).$watch(e,function(a){c.$set(d,a)})})})}function fa(a,b,c){var d=b[0],e=d.parentNode,g,f;if(a){g=0;for(f=a.length;g0){var e=F[0],g=e.text;if(g==a||g==b||g==c||g==d||!a&&!b&&!c&&!d)return e}return!1}function h(b,c,d,g){return(b=i(b,c,d,g))?(a&&!b.json&&e("is not valid json",b),F.shift(),b):!1}function j(a){h(a)||e("is unexpected, expecting ["+a+"]",i())}function g(a,b){return y(function(c,d){return a(c,d,b)},{constant:b.constant})}function m(a,b,c){return y(function(d,e){return b(d,e,a,c)},{constant:a.constant&&c.constant})}function k(){for(var a=[];;)if(F.length>0&&!i("}",")",";","]")&&a.push(fa()), -!h(";"))return a.length==1?a[0]:function(b,c){for(var d,e=0;e","<=",">="))a=m(a,b.fn,r());return a}function p(){for(var a=E(),b;b=h("*","/","%");)a=m(a,b.fn,E());return a}function E(){var a;return h("+")?D():(a=h("-"))?m(A,a.fn,E()):(a=h("!"))?g(a.fn,E()):D()}function D(){var a;if(h("("))a=fa(),j(")");else if(h("["))a=G();else if(h("{"))a=o();else{var b=h();(a=b.fn)||e("not a primary expression",b);if(b.json)a.constant=a.literal=!0}for(var c;b=h("(","[",".");)b.text=== -"("?(a=ea(a,c),c=null):b.text==="["?(c=a,a=z(a)):b.text==="."?(c=a,a=ga(a)):e("IMPOSSIBLE");return a}function G(){var a=[],b=!0;if(f().text!="]"){do{var c=N();a.push(c);c.constant||(b=!1)}while(h(","))}j("]");return y(function(b,c){for(var d=[],e=0;e1;d++){var e=a.shift(),f=b[e];f||(f={},b[e]=f);b=f}return b[a.shift()]=c}function kb(b,a,c){if(!a)return b;for(var a=a.split("."),d,e=b,f=a.length,i=0;ia)for(b in h++,e)e.hasOwnProperty(b)&&!f.hasOwnProperty(b)&&(o--,delete e[b])}else e!==f&&(e=f,h++);return h}, -function(){b(f,e,c)})},$digest:function(){var a,d,e,i,q=this.$$asyncQueue,n,o,r=b,p,E=[],D,G;f("$digest");do{o=!1;for(p=this;q.length;)try{p.$eval(q.shift())}catch(s){c(s)}do{if(i=p.$$watchers)for(n=i.length;n--;)try{if(a=i[n],(d=a.get(p))!==(e=a.last)&&!(a.eq?ja(d,e):typeof d=="number"&&typeof e=="number"&&isNaN(d)&&isNaN(e)))o=!0,a.last=a.eq?W(d):d,a.fn(d,e===h?d:e,p),r<5&&(D=4-r,E[D]||(E[D]=[]),G=I(a.exp)?"fn: "+(a.exp.name||a.exp.toString()):a.exp,G+="; newVal: "+da(d)+"; oldVal: "+da(e),E[D].push(G))}catch(A){c(A)}if(!(i= -p.$$childHead||p!==this&&p.$$nextSibling))for(;p!==this&&!(i=p.$$nextSibling);)p=p.$parent}while(p=i);if(o&&!r--)throw j.$$phase=null,Error(b+" $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: "+da(E));}while(o||q.length);j.$$phase=null},$destroy:function(){if(!(j==this||this.$$destroyed)){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;if(a.$$childHead==this)a.$$childHead=this.$$nextSibling;if(a.$$childTail==this)a.$$childTail=this.$$prevSibling; -if(this.$$prevSibling)this.$$prevSibling.$$nextSibling=this.$$nextSibling;if(this.$$nextSibling)this.$$nextSibling.$$prevSibling=this.$$prevSibling;this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null}},$eval:function(a,b){return d(a)(this,b)},$evalAsync:function(a){this.$$asyncQueue.push(a)},$apply:function(a){try{return f("$apply"),this.$eval(a)}catch(b){c(b)}finally{j.$$phase=null;try{j.$digest()}catch(d){throw c(d),d;}}},$on:function(a,b){var c=this.$$listeners[a]; -c||(this.$$listeners[a]=c=[]);c.push(b);return function(){c[Ga(c,b)]=null}},$emit:function(a,b){var d=[],e,f=this,h=!1,i={name:a,targetScope:f,stopPropagation:function(){h=!0},preventDefault:function(){i.defaultPrevented=!0},defaultPrevented:!1},j=[i].concat(ka.call(arguments,1)),p,o;do{e=f.$$listeners[a]||d;i.currentScope=f;p=0;for(o=e.length;p7),hasEvent:function(a){if(a=="input"&&X==9)return!1;if(u(c[a])){var b=e.createElement("div");c[a]="on"+a in b}return c[a]}, -csp:e.securityPolicy?e.securityPolicy.isActive:!1,vendorPrefix:f,supportsTransitions:j}}]}function Wc(){this.$get=Q(M)}function Qb(b){var a={},c,d,e;if(!b)return a;o(b.split("\n"),function(b){e=b.indexOf(":");c=J(S(b.substr(0,e)));d=S(b.substr(e+1));c&&(a[c]?a[c]+=", "+d:a[c]=d)});return a}function Xc(b,a){var c=Yc.exec(b);if(c==null)return!0;var d={protocol:c[2],host:c[4],port:K(c[6])||Ba[c[2]]||null,relativeProtocol:c[2]===s||c[2]===""},c=lb.exec(a),c={protocol:c[1],host:c[3],port:K(c[5])||Ba[c[1]]|| -null};return(d.protocol==c.protocol||d.relativeProtocol)&&d.host==c.host&&(d.port==c.port||d.relativeProtocol&&c.port==Ba[c.protocol])}function Rb(b){var a=L(b)?b:s;return function(c){a||(a=Qb(b));return c?a[J(c)]||null:a}}function Sb(b,a,c){if(I(c))return c(b,a);o(c,function(c){b=c(b,a)});return b}function Zc(){var b=/^\s*(\[|\{[^\{])/,a=/[\}\]]\s*$/,c=/^\)\]\}',?\n/,d=this.defaults={transformResponse:[function(d){x(d)&&(d=d.replace(c,""),b.test(d)&&a.test(d)&&(d=tb(d,!0)));return d}],transformRequest:[function(a){return L(a)&& -Da.apply(a)!=="[object File]"?da(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},post:{"Content-Type":"application/json;charset=utf-8"},put:{"Content-Type":"application/json;charset=utf-8"}},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN"},e=this.interceptors=[],f=this.responseInterceptors=[];this.$get=["$httpBackend","$browser","$cacheFactory","$rootScope","$q","$injector",function(a,b,c,g,m,k){function l(a){function c(a){var b=y({},a,{data:Sb(a.data,a.headers,e.transformResponse)}); -return 200<=a.status&&a.status<300?b:m.reject(b)}var e={transformRequest:d.transformRequest,transformResponse:d.transformResponse},g={};y(e,a);e.headers=g;e.method=na(e.method);y(g,d.headers.common,d.headers[J(e.method)],a.headers);(a=Xc(e.url,b.url())?b.cookies()[e.xsrfCookieName||d.xsrfCookieName]:s)&&(g[e.xsrfHeaderName||d.xsrfHeaderName]=a);var f=[function(a){var b=Sb(a.data,Rb(g),a.transformRequest);u(a.data)&&delete g["Content-Type"];if(u(a.withCredentials)&&!u(d.withCredentials))a.withCredentials= -d.withCredentials;return q(a,b,g).then(c,c)},s],j=m.when(e);for(o(r,function(a){(a.request||a.requestError)&&f.unshift(a.request,a.requestError);(a.response||a.responseError)&&f.push(a.response,a.responseError)});f.length;)var a=f.shift(),i=f.shift(),j=j.then(a,i);j.success=function(a){j.then(function(b){a(b.data,b.status,b.headers,e)});return j};j.error=function(a){j.then(null,function(b){a(b.data,b.status,b.headers,e)});return j};return j}function q(b,c,e){function f(a,b,c){o&&(200<=a&&a<300?o.put(s, -[a,b,Qb(c)]):o.remove(s));h(b,a,c);g.$apply()}function h(a,c,d){c=Math.max(c,0);(200<=c&&c<300?k.resolve:k.reject)({data:a,status:c,headers:Rb(d),config:b})}function j(){var a=Ga(l.pendingRequests,b);a!==-1&&l.pendingRequests.splice(a,1)}var k=m.defer(),q=k.promise,o,r,s=n(b.url,b.params);l.pendingRequests.push(b);q.then(j,j);if((b.cache||d.cache)&&b.cache!==!1&&b.method=="GET")o=L(b.cache)?b.cache:L(d.cache)?d.cache:B;if(o)if(r=o.get(s))if(r.then)return r.then(j,j),r;else C(r)?h(r[1],r[0],W(r[2])): -h(r,200,{});else o.put(s,q);r||a(b.method,s,c,f,e,b.timeout,b.withCredentials,b.responseType);return q}function n(a,b){if(!b)return a;var c=[];ic(b,function(a,b){a==null||a==s||(C(a)||(a=[a]),o(a,function(a){L(a)&&(a=da(a));c.push(ua(b)+"="+ua(a))}))});return a+(a.indexOf("?")==-1?"?":"&")+c.join("&")}var B=c("$http"),r=[];o(e,function(a){r.unshift(x(a)?k.get(a):k.invoke(a))});o(f,function(a,b){var c=x(a)?k.get(a):k.invoke(a);r.splice(b,0,{response:function(a){return c(m.when(a))},responseError:function(a){return c(m.reject(a))}})}); -l.pendingRequests=[];(function(a){o(arguments,function(a){l[a]=function(b,c){return l(y(c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){o(arguments,function(a){l[a]=function(b,c,d){return l(y(d||{},{method:a,url:b,data:c}))}})})("post","put");l.defaults=d;return l}]}function $c(){this.$get=["$browser","$window","$document",function(b,a,c){return ad(b,bd,b.defer,a.angular.callbacks,c[0],a.location.protocol.replace(":",""))}]}function ad(b,a,c,d,e,f){function i(a,b){var c= -e.createElement("script"),d=function(){e.body.removeChild(c);b&&b()};c.type="text/javascript";c.src=a;X?c.onreadystatechange=function(){/loaded|complete/.test(c.readyState)&&d()}:c.onload=c.onerror=d;e.body.appendChild(c)}return function(e,j,g,m,k,l,q,n){function B(a,c,d,e){c=(j.match(lb)||["",f])[1]=="file"?d?200:404:c;a(c==1223?204:c,d,e);b.$$completeOutstandingRequest(t)}b.$$incOutstandingRequestCount();j=j||b.url();if(J(e)=="jsonp"){var r="_"+(d.counter++).toString(36);d[r]=function(a){d[r].data= -a};i(j.replace("JSON_CALLBACK","angular.callbacks."+r),function(){d[r].data?B(m,200,d[r].data):B(m,-2);delete d[r]})}else{var p=new a;p.open(e,j,!0);o(k,function(a,b){a&&p.setRequestHeader(b,a)});var s;p.onreadystatechange=function(){if(p.readyState==4){var a=p.getAllResponseHeaders(),b=["Cache-Control","Content-Language","Content-Type","Expires","Last-Modified","Pragma"];a||(a="",o(b,function(b){var c=p.getResponseHeader(b);c&&(a+=b+": "+c+"\n")}));B(m,s||p.status,p.responseType?p.response:p.responseText, -a)}};if(q)p.withCredentials=!0;if(n)p.responseType=n;p.send(g||"");l>0&&c(function(){s=-1;p.abort()},l)}}}function cd(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January,February,March,April,May,June,July,August,September,October,November,December".split(","), -SHORTMONTH:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(","),DAY:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(","),SHORTDAY:"Sun,Mon,Tue,Wed,Thu,Fri,Sat".split(","),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a"},pluralCat:function(b){return b===1?"one":"other"}}}}function dd(){this.$get=["$rootScope","$browser","$q", -"$exceptionHandler",function(b,a,c,d){function e(e,h,j){var g=c.defer(),m=g.promise,k=w(j)&&!j,h=a.defer(function(){try{g.resolve(e())}catch(a){g.reject(a),d(a)}k||b.$apply()},h),j=function(){delete f[m.$$timeoutId]};m.$$timeoutId=h;f[h]=g;m.then(j,j);return m}var f={};e.cancel=function(b){return b&&b.$$timeoutId in f?(f[b.$$timeoutId].reject("canceled"),a.defer.cancel(b.$$timeoutId)):!1};return e}]}function Tb(b){function a(a,e){return b.factory(a+c,e)}var c="Filter";this.register=a;this.$get=["$injector", -function(a){return function(b){return a.get(b+c)}}];a("currency",Ub);a("date",Vb);a("filter",ed);a("json",fd);a("limitTo",gd);a("lowercase",hd);a("number",Wb);a("orderBy",Xb);a("uppercase",id)}function ed(){return function(b,a,c){if(!C(b))return b;var d=[];d.check=function(a){for(var b=0;b-1}}var e=function(a,b){if(typeof b=="string"&&b.charAt(0)==="!")return!e(a,b.substr(1));switch(typeof a){case "boolean":case "number":case "string":return c(a,b);case "object":switch(typeof b){case "object":return c(a,b);default:for(var d in a)if(d.charAt(0)!=="$"&&e(a[d],b))return!0}return!1;case "array":for(d=0;de+1?i="0":(h=i,g=!0)}if(!g){i=(i.split(Zb)[1]||"").length;u(e)&&(e=Math.min(Math.max(a.minFrac,i),a.maxFrac));var i=Math.pow(10,e),b=Math.round(b*i)/i,b=(""+b).split(Zb),i=b[0],b=b[1]||"",g=0,m=a.lgSize,k=a.gSize;if(i.length>=m+k)for(var g=i.length-m,l=0;l0||e>-c)e+=c;e===0&&c==-12&&(e=12);return ob(e,a,d)}}function Sa(b,a){return function(c, -d){var e=c["get"+b](),f=na(a?"SHORT"+b:b);return d[f][e]}}function Vb(b){function a(a){var b;if(b=a.match(c)){var a=new Date(0),f=0,i=0,h=b[8]?a.setUTCFullYear:a.setFullYear,j=b[8]?a.setUTCHours:a.setHours;b[9]&&(f=K(b[9]+b[10]),i=K(b[9]+b[11]));h.call(a,K(b[1]),K(b[2])-1,K(b[3]));j.call(a,K(b[4]||0)-f,K(b[5]||0)-i,K(b[6]||0),K(b[7]||0))}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,e){var f="",i=[],h,j,e=e|| -"mediumDate",e=b.DATETIME_FORMATS[e]||e;x(c)&&(c=jd.test(c)?K(c):a(c));Za(c)&&(c=new Date(c));if(!qa(c))return c;for(;e;)(j=kd.exec(e))?(i=i.concat(ka.call(j,1)),e=i.pop()):(i.push(e),e=null);o(i,function(a){h=ld[a];f+=h?h(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return f}}function fd(){return function(b){return da(b,!0)}}function gd(){return function(b,a){if(!C(b)&&!x(b))return b;a=K(a);if(x(b))return a?a>=0?b.slice(0,a):b.slice(a,b.length):"";var c=[],d,e;a>b.length?a= -b.length:a<-b.length&&(a=-b.length);a>0?(d=0,e=a):(d=b.length+a,e=b.length);for(;dk?(d.$setValidity("maxlength",!1),s):(d.$setValidity("maxlength",!0),a)};d.$parsers.push(e);d.$formatters.push(e)}}function pb(b,a){b="ngClass"+b;return Y(function(c,d,e){function f(b){if(a=== -!0||c.$index%2===a)j&&b!==j&&i(j),h(b);j=b}function i(a){L(a)&&!C(a)&&(a=$a(a,function(a,b){if(a)return b}));d.removeClass(C(a)?a.join(" "):a)}function h(a){L(a)&&!C(a)&&(a=$a(a,function(a,b){if(a)return b}));a&&d.addClass(C(a)?a.join(" "):a)}var j=s;c.$watch(e[b],f,!0);e.$observe("class",function(){var a=c.$eval(e[b]);f(a,a)});b!=="ngClass"&&c.$watch("$index",function(d,f){var j=d%2;j!==f%2&&(j==a?h(c.$eval(e[b])):i(c.$eval(e[b])))})})}var J=function(b){return x(b)?b.toLowerCase():b},na=function(b){return x(b)? -b.toUpperCase():b},X=K((/msie (\d+)/.exec(J(navigator.userAgent))||[])[1]),v,ca,ka=[].slice,Ya=[].push,Da=Object.prototype.toString,hc=M.angular,Ia=M.angular||(M.angular={}),xa,jb,Z=["0","0","0"];t.$inject=[];pa.$inject=[];jb=X<9?function(b){b=b.nodeName?b:b[0];return b.scopeName&&b.scopeName!="HTML"?na(b.scopeName+":"+b.nodeName):b.nodeName}:function(b){return b.nodeName?b.nodeName:b[0].nodeName};var nc=/[A-Z]/g,md={full:"1.1.4",major:1,minor:1,dot:4,codeName:"quantum-manipulation"},La=P.cache={}, -Ka=P.expando="ng-"+(new Date).getTime(),rc=1,ac=M.document.addEventListener?function(b,a,c){b.addEventListener(a,c,!1)}:function(b,a,c){b.attachEvent("on"+a,c)},ib=M.document.removeEventListener?function(b,a,c){b.removeEventListener(a,c,!1)}:function(b,a,c){b.detachEvent("on"+a,c)},pc=/([\:\-\_]+(.))/g,qc=/^moz([A-Z])/,za=P.prototype={ready:function(b){function a(){c||(c=!0,b())}var c=!1;V.readyState==="complete"?setTimeout(a):(this.bind("DOMContentLoaded",a),P(M).bind("load",a))},toString:function(){var b= -[];o(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return b>=0?v(this[b]):v(this[this.length+b])},length:0,push:Ya,sort:[].sort,splice:[].splice},Oa={};o("multiple,selected,checked,disabled,readOnly,required,open".split(","),function(b){Oa[J(b)]=b});var Eb={};o("input,select,option,textarea,button,form,details".split(","),function(b){Eb[na(b)]=!0});o({data:zb,inheritedData:Na,scope:function(b){return Na(b,"$scope")},controller:Cb,injector:function(b){return Na(b,"$injector")}, -removeAttr:function(b,a){b.removeAttribute(a)},hasClass:Ma,css:function(b,a,c){a=Ja(a);if(w(c))b.style[a]=c;else{var d;X<=8&&(d=b.currentStyle&&b.currentStyle[a],d===""&&(d="auto"));d=d||b.style[a];X<=8&&(d=d===""?s:d);return d}},attr:function(b,a,c){var d=J(a);if(Oa[d])if(w(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||t).specified?d:s;else if(w(c))b.setAttribute(a,c);else if(b.getAttribute)return b=b.getAttribute(a,2),b===null? -s:b},prop:function(b,a,c){if(w(c))b[a]=c;else return b[a]},text:y(X<9?function(b,a){if(b.nodeType==1){if(u(a))return b.innerText;b.innerText=a}else{if(u(a))return b.nodeValue;b.nodeValue=a}}:function(b,a){if(u(a))return b.textContent;b.textContent=a},{$dv:""}),val:function(b,a){if(u(a))return b.value;b.value=a},html:function(b,a){if(u(a))return b.innerHTML;for(var c=0,d=b.childNodes;c":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a,c,d,e){return d(a,c)<=e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a, -c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"&":function(a,c,d,e){return d(a,c)&e(a,c)},"|":function(a,c,d,e){return e(a,c)(a,c,d(a,c))},"!":function(a,c,d){return!d(a,c)}},Nc={n:"\n",f:"\u000c",r:"\r",t:"\t",v:"\u000b","'":"'",'"':'"'},nb={},Yc=/^(([^:]+):)?\/\/(\w+:{0,1}\w*@)?([\w\.-]*)?(:([0-9]+))?(.*)$/,bd=M.XMLHttpRequest||function(){try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(c){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(d){}throw Error("This browser does not support XMLHttpRequest."); -};Tb.$inject=["$provide"];Ub.$inject=["$locale"];Wb.$inject=["$locale"];var Zb=".",ld={yyyy:O("FullYear",4),yy:O("FullYear",2,0,!0),y:O("FullYear",1),MMMM:Sa("Month"),MMM:Sa("Month",!0),MM:O("Month",2,1),M:O("Month",1,1),dd:O("Date",2),d:O("Date",1),HH:O("Hours",2),H:O("Hours",1),hh:O("Hours",2,-12),h:O("Hours",1,-12),mm:O("Minutes",2),m:O("Minutes",1),ss:O("Seconds",2),s:O("Seconds",1),sss:O("Milliseconds",3),EEEE:Sa("Day"),EEE:Sa("Day",!0),a:function(a,c){return a.getHours()<12?c.AMPMS[0]:c.AMPMS[1]}, -Z:function(a){var a=-1*a.getTimezoneOffset(),c=a>=0?"+":"";c+=ob(Math[a>0?"floor":"ceil"](a/60),2)+ob(Math.abs(a%60),2);return c}},kd=/((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,jd=/^\d+$/;Vb.$inject=["$locale"];var hd=Q(J),id=Q(na);Xb.$inject=["$parse"];var od=Q({restrict:"E",compile:function(a,c){X<=8&&(!c.href&&!c.name&&c.$set("href",""),a.append(V.createComment("IE fix")));return function(a,c){c.bind("click",function(a){c.attr("href")||a.preventDefault()})}}}), -qb={};o(Oa,function(a,c){var d=aa("ng-"+c);qb[d]=function(){return{priority:100,compile:function(){return function(a,f,i){a.$watch(i[d],function(a){i.$set(c,!!a)})}}}}});o(["src","href"],function(a){var c=aa("ng-"+a);qb[c]=function(){return{priority:99,link:function(d,e,f){f.$observe(c,function(c){c&&(f.$set(a,c),X&&e.prop(a,f[a]))})}}}});var Va={$addControl:t,$removeControl:t,$setValidity:t,$setDirty:t,$setPristine:t};$b.$inject=["$element","$attrs","$scope"];var Ya=function(a){return["$timeout", -function(c){var d={name:"form",restrict:"E",controller:$b,compile:function(){return{pre:function(a,d,i,h){if(!i.action){var j=function(a){a.preventDefault?a.preventDefault():a.returnValue=!1};ac(d[0],"submit",j);d.bind("$destroy",function(){c(function(){ib(d[0],"submit",j)},0,!1)})}var g=d.parent().controller("form"),m=i.name||i.ngForm;m&&(a[m]=h);g&&d.bind("$destroy",function(){g.$removeControl(h);m&&(a[m]=s);y(h,Va)})}}}};return a?y(W(d),{restrict:"EAC"}):d}]},pd=Ya(),qd=Ya(!0),rd=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/, -sd=/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/,td=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/,cc={text:Xa,number:function(a,c,d,e,f,i){Xa(a,c,d,e,f,i);e.$parsers.push(function(a){var c=U(a);return c||td.test(a)?(e.$setValidity("number",!0),a===""?null:c?a:parseFloat(a)):(e.$setValidity("number",!1),s)});e.$formatters.push(function(a){return U(a)?"":""+a});if(d.min){var h=parseFloat(d.min),a=function(a){return!U(a)&&aj?(e.$setValidity("max",!1),s):(e.$setValidity("max",!0),a)};e.$parsers.push(d);e.$formatters.push(d)}e.$formatters.push(function(a){return U(a)||Za(a)?(e.$setValidity("number",!0),a):(e.$setValidity("number",!1),s)})},url:function(a,c,d,e,f,i){Xa(a,c,d,e,f,i);a=function(a){return U(a)||rd.test(a)?(e.$setValidity("url",!0),a):(e.$setValidity("url",!1),s)};e.$formatters.push(a);e.$parsers.push(a)},email:function(a, -c,d,e,f,i){Xa(a,c,d,e,f,i);a=function(a){return U(a)||sd.test(a)?(e.$setValidity("email",!0),a):(e.$setValidity("email",!1),s)};e.$formatters.push(a);e.$parsers.push(a)},radio:function(a,c,d,e){u(d.name)&&c.attr("name",Ea());c.bind("click",function(){c[0].checked&&a.$apply(function(){e.$setViewValue(d.value)})});e.$render=function(){c[0].checked=d.value==e.$viewValue};d.$observe("value",e.$render)},checkbox:function(a,c,d,e){var f=d.ngTrueValue,i=d.ngFalseValue;x(f)||(f=!0);x(i)||(i=!1);c.bind("click", -function(){a.$apply(function(){e.$setViewValue(c[0].checked)})});e.$render=function(){c[0].checked=e.$viewValue};e.$formatters.push(function(a){return a===f});e.$parsers.push(function(a){return a?f:i})},hidden:t,button:t,submit:t,reset:t},dc=["$browser","$sniffer",function(a,c){return{restrict:"E",require:"?ngModel",link:function(d,e,f,i){i&&(cc[J(f.type)]||cc.text)(d,e,f,i,c,a)}}}],Ua="ng-valid",Ta="ng-invalid",oa="ng-pristine",Wa="ng-dirty",ud=["$scope","$exceptionHandler","$attrs","$element","$parse", -function(a,c,d,e,f){function i(a,c){c=c?"-"+db(c,"-"):"";e.removeClass((a?Ta:Ua)+c).addClass((a?Ua:Ta)+c)}this.$modelValue=this.$viewValue=Number.NaN;this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$name=d.name;var h=f(d.ngModel),j=h.assign;if(!j)throw Error(Ib+d.ngModel+" ("+ta(e)+")");this.$render=t;var g=e.inheritedData("$formController")||Va,m=0,k=this.$error={};e.addClass(oa);i(!0);this.$setValidity=function(a, -c){if(k[a]!==!c){if(c){if(k[a]&&m--,!m)i(!0),this.$valid=!0,this.$invalid=!1}else i(!1),this.$invalid=!0,this.$valid=!1,m++;k[a]=!c;i(c,a);g.$setValidity(a,c,this)}};this.$setPristine=function(){this.$dirty=!1;this.$pristine=!0;e.removeClass(Wa).addClass(oa)};this.$setViewValue=function(d){this.$viewValue=d;if(this.$pristine)this.$dirty=!0,this.$pristine=!1,e.removeClass(oa).addClass(Wa),g.$setDirty();o(this.$parsers,function(a){d=a(d)});if(this.$modelValue!==d)this.$modelValue=d,j(a,d),o(this.$viewChangeListeners, -function(a){try{a()}catch(d){c(d)}})};var l=this;a.$watch(function(){var c=h(a);if(l.$modelValue!==c){var d=l.$formatters,e=d.length;for(l.$modelValue=c;e--;)c=d[e](c);if(l.$viewValue!==c)l.$viewValue=c,l.$render()}})}],vd=function(){return{require:["ngModel","^?form"],controller:ud,link:function(a,c,d,e){var f=e[0],i=e[1]||Va;i.$addControl(f);c.bind("$destroy",function(){i.$removeControl(f)})}}},wd=Q({require:"ngModel",link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}), -ec=function(){return{require:"?ngModel",link:function(a,c,d,e){if(e){d.required=!0;var f=function(a){if(d.required&&(U(a)||a===!1))e.$setValidity("required",!1);else return e.$setValidity("required",!0),a};e.$formatters.push(f);e.$parsers.unshift(f);d.$observe("required",function(){f(e.$viewValue)})}}}},xd=function(){return{require:"ngModel",link:function(a,c,d,e){var f=(a=/\/(.*)\//.exec(d.ngList))&&RegExp(a[1])||d.ngList||",";e.$parsers.push(function(a){var c=[];a&&o(a.split(f),function(a){a&&c.push(S(a))}); -return c});e.$formatters.push(function(a){return C(a)?a.join(", "):s})}}},yd=/^(true|false|\d+)$/,zd=function(){return{priority:100,compile:function(a,c){return yd.test(c.ngValue)?function(a,c,f){f.$set("value",a.$eval(f.ngValue))}:function(a,c,f){a.$watch(f.ngValue,function(a){f.$set("value",a,!1)})}}}},Ad=Y(function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBind);a.$watch(d.ngBind,function(a){c.text(a==s?"":a)})}),Bd=["$interpolate",function(a){return function(c,d,e){c=a(d.attr(e.$attr.ngBindTemplate)); -d.addClass("ng-binding").data("$binding",c);e.$observe("ngBindTemplate",function(a){d.text(a)})}}],Cd=[function(){return function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBindHtmlUnsafe);a.$watch(d.ngBindHtmlUnsafe,function(a){c.html(a||"")})}}],Dd=pb("",!0),Ed=pb("Odd",0),Fd=pb("Even",1),Gd=Y({compile:function(a,c){c.$set("ngCloak",s);a.removeClass("ng-cloak")}}),Hd=[function(){return{scope:!0,controller:"@"}}],Id=["$sniffer",function(a){return{priority:1E3,compile:function(){a.csp=!0}}}], -fc={};o("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress".split(" "),function(a){var c=aa("ng-"+a);fc[c]=["$parse",function(d){return function(e,f,i){var h=d(i[c]);f.bind(J(a),function(a){e.$apply(function(){h(e,{$event:a})})})}}]});var Jd=Y(function(a,c,d){c.bind("submit",function(){a.$apply(d.ngSubmit)})}),Kd=["$http","$templateCache","$anchorScroll","$compile","$animator",function(a,c,d,e,f){return{restrict:"ECA",terminal:!0,compile:function(i, -h){var j=h.ngInclude||h.src,g=h.onload||"",m=h.autoscroll;return function(h,i,o){var n=f(h,o),s=0,r,p=function(){r&&(r.$destroy(),r=null);n.leave(i.contents(),i)};h.$watch(j,function(f){var j=++s;f?a.get(f,{cache:c}).success(function(a){j===s&&(r&&r.$destroy(),r=h.$new(),n.leave(i.contents(),i),a=v("
").html(a).contents(),n.enter(a,i),e(a)(r),w(m)&&(!m||h.$eval(m))&&d(),r.$emit("$includeContentLoaded"),h.$eval(g))}).error(function(){j===s&&p()}):p()})}}}}],Ld=Y({compile:function(){return{pre:function(a, -c,d){a.$eval(d.ngInit)}}}}),Md=Y({terminal:!0,priority:1E3}),Nd=["$locale","$interpolate",function(a,c){var d=/{}/g;return{restrict:"EA",link:function(e,f,i){var h=i.count,j=f.attr(i.$attr.when),g=i.offset||0,m=e.$eval(j),k={},l=c.startSymbol(),q=c.endSymbol();o(m,function(a,e){k[e]=c(a.replace(d,l+h+"-"+g+q))});e.$watch(function(){var c=parseFloat(e.$eval(h));return isNaN(c)?"":(m[c]||(c=a.pluralCat(c-g)),k[c](e,f,!0))},function(a){f.text(a)})}}}],Od=["$parse","$animator",function(a,c){return{transclude:"element", -priority:1E3,terminal:!0,compile:function(d,e,f){return function(d,e,j){var g=c(d,j),m=j.ngRepeat,k=m.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),l,q,n,s,r,p={$id:la};if(!k)throw Error("Expected ngRepeat in form of '_item_ in _collection_[ track by _id_]' but got '"+m+"'.");j=k[1];n=k[2];(k=k[4])?(l=a(k),q=function(a,c,e){r&&(p[r]=a);p[s]=c;p.$index=e;return l(d,p)}):q=function(a,c){return la(c)};k=j.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);if(!k)throw Error("'item' in 'item in collection' should be identifier or (key, value) but got '"+ -j+"'.");s=k[3]||k[1];r=k[2];var y={};d.$watchCollection(n,function(a){var c,j,k=e,l,n={},p,t,v,z,w,u,x=[];if(C(a))w=a;else{w=[];for(v in a)a.hasOwnProperty(v)&&v.charAt(0)!="$"&&w.push(v);w.sort()}p=w.length;j=x.length=w.length;for(c=0;c
").html(k).contents(),c);var k=f(c.contents()),m=d.current;l=m.scope=a.$new();if(m.controller)h.$scope=l,h=i(m.controller,h),c.children().data("$ngControllerController",h);k(l);l.$emit("$viewContentLoaded");l.$eval(o);e()}else n.leave(c.contents(),c),l&&(l.$destroy(),l=null)}var l,o=m.onload||"",n=h(a,m);a.$on("$routeChangeSuccess",k);k()}}}],Xd=["$templateCache",function(a){return{restrict:"E",terminal:!0,compile:function(c, -d){d.type=="text/ng-template"&&a.put(d.id,c[0].text)}}}],Yd=Q({terminal:!0}),Zd=["$compile","$parse",function(a,c){var d=/^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/,e={$setViewValue:t};return{restrict:"E",require:["select","?ngModel"],controller:["$element","$scope","$attrs",function(a,c,d){var j=this,g={},m=e,k;j.databound=d.ngModel;j.init=function(a,c,d){m=a;k=d};j.addOption=function(c){g[c]= -!0;m.$viewValue==c&&(a.val(c),k.parent()&&k.remove())};j.removeOption=function(a){this.hasOption(a)&&(delete g[a],m.$viewValue==a&&this.renderUnknownOption(a))};j.renderUnknownOption=function(c){c="? "+la(c)+" ?";k.val(c);a.prepend(k);a.val(c);k.prop("selected",!0)};j.hasOption=function(a){return g.hasOwnProperty(a)};c.$on("$destroy",function(){j.renderUnknownOption=t})}],link:function(e,i,h,j){function g(a,c,d,e){d.$render=function(){var a=d.$viewValue;e.hasOption(a)?(x.parent()&&x.remove(),c.val(a), -a===""&&p.prop("selected",!0)):u(a)&&p?c.val(""):e.renderUnknownOption(a)};c.bind("change",function(){a.$apply(function(){x.parent()&&x.remove();d.$setViewValue(c.val())})})}function m(a,c,d){var e;d.$render=function(){var a=new Pa(d.$viewValue);o(c.find("option"),function(c){c.selected=w(a.get(c.value))})};a.$watch(function(){ja(e,d.$viewValue)||(e=W(d.$viewValue),d.$render())});c.bind("change",function(){a.$apply(function(){var a=[];o(c.find("option"),function(c){c.selected&&a.push(c.value)});d.$setViewValue(a)})})} -function k(e,f,h){function g(){var a={"":[]},c=[""],d,i,t,v,u;t=h.$modelValue;v=p(e)||[];var w=l?rb(v):v,z,x,A;x={};u=!1;var B,C;if(n)u=new Pa(t);else if(t===null||r)a[""].push({selected:t===null,id:"",label:""}),u=!0;for(A=0;z=w.length,AA;)v.pop().element.remove()}for(;q.length>x;)q.pop()[0].element.remove()}var i;if(!(i=t.match(d)))throw Error("Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '"+t+"'.");var j=c(i[2]||i[1]),k=i[4]||i[6],l=i[5],m=c(i[3]||""),o=c(i[2]?i[1]:k),p=c(i[7]),q=[[{element:f,label:""}]];r&&(a(r)(e),r.removeClass("ng-scope"),r.remove());f.html("");f.bind("change", -function(){e.$apply(function(){var a,c=p(e)||[],d={},g,i,j,m,r,t;if(n){i=[];m=0;for(t=q.length;m@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none;}ng\\:form{display:block;}'); +(function(M,T,p){'use strict';function lc(){var b=M.angular;M.angular=mc;return b}function Xa(b){return!b||typeof b.length!=="number"?!1:typeof b.hasOwnProperty!="function"&&typeof b.constructor!="function"?!0:b instanceof R||ga&&b instanceof ga||Ea.call(b)!=="[object Object]"||typeof b.callee==="function"}function n(b,a,c){var d;if(b)if(H(b))for(d in b)d!="prototype"&&d!="length"&&d!="name"&&b.hasOwnProperty(d)&&a.call(c,b[d],d);else if(b.forEach&&b.forEach!==n)b.forEach(a,c);else if(Xa(b))for(d= +0;d=0&&b.splice(c,1);return a}function V(b,a){if(sa(b)||b&&b.$evalAsync&&b.$watch)throw Error("Can't copy Window or Scope");if(a){if(b===a)throw Error("Can't copy equivalent objects or arrays");if(F(b))for(var c=a.length=0;c2?ka.call(arguments,2):[];return H(a)&&!(a instanceof RegExp)?c.length?function(){return arguments.length?a.apply(b,c.concat(ka.call(arguments,0))):a.apply(b,c)}:function(){return arguments.length?a.apply(b,arguments):a.call(b)}:a}function qc(b,a){var c=a;/^\$+/.test(b)?c=p:sa(a)?c="$WINDOW":a&&T===a?c="$DOCUMENT":a&&a.$evalAsync&& +a.$watch&&(c="$SCOPE");return c}function ha(b,a){return JSON.stringify(b,qc,a?" ":null)}function ub(b){return E(b)?JSON.parse(b):b}function ua(b){b&&b.length!==0?(b=I(""+b),b=!(b=="f"||b=="0"||b=="false"||b=="no"||b=="n"||b=="[]")):b=!1;return b}function va(b){b=w(b).clone();try{b.html("")}catch(a){}var c=w("
").append(b).html();try{return b[0].nodeType===3?I(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+I(b)})}catch(d){return I(c)}}function vb(b){var a={},c,d;n((b|| +"").split("&"),function(b){b&&(c=b.split("="),d=decodeURIComponent(c[0]),a[d]=B(c[1])?decodeURIComponent(c[1]):!0)});return a}function wb(b){var a=[];n(b,function(b,d){a.push(wa(d,!0)+(b===!0?"":"="+wa(b,!0)))});return a.length?a.join("&"):""}function ab(b){return wa(b,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function wa(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,a?"%20":"+")}function rc(b, +a){function c(a){a&&d.push(a)}var d=[b],e,g,i=["ng:app","ng-app","x-ng-app","data-ng-app"],f=/\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;n(i,function(a){i[a]=!0;c(T.getElementById(a));a=a.replace(":","\\:");b.querySelectorAll&&(n(b.querySelectorAll("."+a),c),n(b.querySelectorAll("."+a+"\\:"),c),n(b.querySelectorAll("["+a+"]"),c))});n(d,function(a){if(!e){var b=f.exec(" "+a.className+" ");b?(e=a,g=(b[2]||"").replace(/\s+/g,",")):n(a.attributes,function(b){if(!e&&i[b.name])e=a,g=b.value})}});e&&a(e,g?[g]:[])} +function xb(b,a){var c=function(){b=w(b);a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);a.unshift("ng");var c=yb(a);c.invoke(["$rootScope","$rootElement","$compile","$injector","$animator",function(a,b,c,d,e){a.$apply(function(){b.data("$injector",d);c(b)(a)});e.enabled(!0)}]);return c},d=/^NG_DEFER_BOOTSTRAP!/;if(M&&!d.test(M.name))return c();M.name=M.name.replace(d,"");Ha.resumeBootstrap=function(b){n(b,function(b){a.push(b)});c()}}function bb(b,a){a=a||"_";return b.replace(sc, +function(b,d){return(d?a:"")+b.toLowerCase()})}function cb(b,a,c){if(!b)throw Error("Argument '"+(a||"?")+"' is "+(c||"required"));return b}function xa(b,a,c){c&&F(b)&&(b=b[b.length-1]);cb(H(b),a,"not a function, got "+(b&&typeof b=="object"?b.constructor.name||"Object":typeof b));return b}function tc(b){function a(a,b,e){return a[b]||(a[b]=e())}return a(a(b,"angular",Object),"module",function(){var b={};return function(d,e,g){e&&b.hasOwnProperty(d)&&(b[d]=null);return a(b,d,function(){function a(c, +d,e){return function(){b[e||"push"]([c,d,arguments]);return m}}if(!e)throw Error("No module: "+d);var b=[],c=[],j=a("$injector","invoke"),m={_invokeQueue:b,_runBlocks:c,requires:e,name:d,provider:a("$provide","provider"),factory:a("$provide","factory"),service:a("$provide","service"),value:a("$provide","value"),constant:a("$provide","constant","unshift"),animation:a("$animationProvider","register"),filter:a("$filterProvider","register"),controller:a("$controllerProvider","register"),directive:a("$compileProvider", +"directive"),config:j,run:function(a){c.push(a);return this}};g&&j(g);return m})}})}function Ia(b){return b.replace(uc,function(a,b,d,e){return e?d.toUpperCase():d}).replace(vc,"Moz$1")}function db(b,a){function c(){var e;for(var b=[this],c=a,i,f,h,j,m,k;b.length;){i=b.shift();f=0;for(h=i.length;f 
"+b;a.removeChild(a.firstChild);eb(this,a.childNodes);this.remove()}else eb(this,b)}function fb(b){return b.cloneNode(!0)}function ya(b){zb(b);for(var a=0,b=b.childNodes||[];a-1}function Cb(b,a){a&&n(a.split(" "),function(a){b.className=U((" "+b.className+" ").replace(/[\n\t]/g," ").replace(" "+U(a)+" "," "))})}function Db(b,a){a&&n(a.split(" "),function(a){if(!La(b,a))b.className=U(b.className+" "+U(a))})}function eb(b,a){if(a)for(var a=!a.nodeName&&B(a.length)&&!sa(a)?a:[a],c=0;c 4096 bytes)!")}else{if(h.cookie!==D){D=h.cookie;d=D.split("; ");G={};for(f=0;f0&&(a=unescape(e.substring(0,j)),G[a]===p&&(G[a]=unescape(e.substring(j+1))))}return G}};f.defer=function(a,b){var c;o++;c=k(function(){delete u[c];e(a)},b||0);u[c]=!0;return c};f.defer.cancel=function(a){return u[a]?(delete u[a],l(a),e(q),!0):!1}}function Ec(){this.$get= +["$window","$log","$sniffer","$document",function(b,a,c,d){return new Dc(b,d,a,c)}]}function Fc(){this.$get=function(){function b(b,d){function e(a){if(a!=k){if(l){if(l==a)l=a.n}else l=a;g(a.n,a.p);g(a,k);k=a;k.n=null}}function g(a,b){if(a!=b){if(a)a.p=b;if(b)b.n=a}}if(b in a)throw Error("cacheId "+b+" taken");var i=0,f=t({},d,{id:b}),h={},j=d&&d.capacity||Number.MAX_VALUE,m={},k=null,l=null;return a[b]={put:function(a,b){var c=m[a]||(m[a]={key:a});e(c);if(!C(b))return a in h||i++,h[a]=b,i>j&&this.remove(l.key), +b},get:function(a){var b=m[a];if(b)return e(b),h[a]},remove:function(a){var b=m[a];if(b){if(b==k)k=b.p;if(b==l)l=b.n;g(b.n,b.p);delete m[a];delete h[a];i--}},removeAll:function(){h={};i=0;m={};k=l=null},destroy:function(){m=f=h=null;delete a[b]},info:function(){return t({},f,{size:i})}}}var a={};b.info=function(){var b={};n(a,function(a,e){b[e]=a.info()});return b};b.get=function(b){return a[b]};return b}}function Gc(){this.$get=["$cacheFactory",function(b){return b("templates")}]}function Jb(b){var a= +{},c="Directive",d=/^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,e=/(([\d\w\-_]+)(?:\:([^;]+))?;?)/,g="Template must have exactly one root element. was: ",i=/^\s*(https?|ftp|mailto|file):/;this.directive=function h(d,e){E(d)?(cb(e,"directive"),a.hasOwnProperty(d)||(a[d]=[],b.factory(d+c,["$injector","$exceptionHandler",function(b,c){var e=[];n(a[d],function(a){try{var g=b.invoke(a);if(H(g))g={compile:S(g)};else if(!g.compile&&g.link)g.compile=S(g.link);g.priority=g.priority||0;g.name=g.name||d;g.require= +g.require||g.controller&&g.name;g.restrict=g.restrict||"A";e.push(g)}catch(h){c(h)}});return e}])),a[d].push(e)):n(d,rb(h));return this};this.urlSanitizationWhitelist=function(a){return B(a)?(i=a,this):i};this.$get=["$injector","$interpolate","$exceptionHandler","$http","$templateCache","$parse","$controller","$rootScope","$document",function(b,j,m,k,l,u,o,z,r){function y(a,b,c){a instanceof w||(a=w(a));n(a,function(b,c){b.nodeType==3&&b.nodeValue.match(/\S+/)&&(a[c]=w(b).wrap("").parent()[0])}); +var d=W(a,b,a,c);return function(b,c){cb(b,"scope");for(var e=c?Ba.clone.call(a):a,j=0,g=e.length;js.priority)break;if(t=s.scope)O("isolated scope",K,s,J),L(t)&&(x(J,"ng-isolate-scope"),K=s),x(J,"ng-scope"),r=r||s;A=s.name;if(t=s.controller)q=q||{},O("'"+A+"' controller",q[A],s,J),q[A]=s;if(t=s.transclude)O("transclusion",G,s,J),G=s,l=s.priority,t=="element"?(Y=w(b),J=c.$$element=w(T.createComment(" "+A+": "+c[A]+" ")),b=J[0],ja(e,w(Y[0]),b),P=y(Y,d,l)):(Y=w(fb(b)).contents(), +J.html(""),P=y(Y,d));if(s.template)if(O("template",W,s,J),W=s,t=H(s.template)?s.template(J,c):s.template,t=Lb(t),s.replace){Y=w("
"+U(t)+"
").contents();b=Y[0];if(Y.length!=1||b.nodeType!==1)throw Error(g+t);ja(e,J,b);A={$attr:{}};a=a.concat(v(b,a.splice(B+1,a.length-(B+1)),A));D(c,A);C=a.length}else J.html(t);if(s.templateUrl)O("template",W,s,J),W=s,k=$(a.splice(B,a.length-B),k,J,c,e,s.replace,P),C=a.length;else if(s.compile)try{na=s.compile(J,c,P),H(na)?h(null,na):na&&h(na.pre,na.post)}catch(I){m(I, +va(J))}if(s.terminal)k.terminal=!0,l=Math.max(l,s.priority)}k.scope=r&&r.scope;k.transclude=G&&P;return k}function G(d,e,j,g){var l=!1;if(a.hasOwnProperty(e))for(var k,e=b.get(e+c),i=0,o=e.length;ik.priority)&&k.restrict.indexOf(j)!=-1)d.push(k),l=!0}catch(u){m(u)}return l}function D(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;n(a,function(d,e){e.charAt(0)!="$"&&(b[e]&&(d+=(e==="style"?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});n(b,function(b,j){j=="class"?(x(e,b),a["class"]= +(a["class"]?a["class"]+" ":"")+b):j=="style"?e.attr("style",e.attr("style")+";"+b):j.charAt(0)!="$"&&!a.hasOwnProperty(j)&&(a[j]=b,d[j]=c[j])})}function $(a,b,c,d,e,j,h){var i=[],o,m,u=c[0],z=a.shift(),r=t({},z,{controller:null,templateUrl:null,transclude:null,scope:null}),z=H(z.templateUrl)?z.templateUrl(c,d):z.templateUrl;c.html("");k.get(z,{cache:l}).success(function(l){var k,z,l=Lb(l);if(j){z=w("
"+U(l)+"
").contents();k=z[0];if(z.length!=1||k.nodeType!==1)throw Error(g+l);l={$attr:{}}; +ja(e,c,k);v(k,a,l);D(d,l)}else k=u,c.html(l);a.unshift(r);o=A(a,k,d,h);for(m=W(c[0].childNodes,h);i.length;){var ea=i.shift(),l=i.shift();z=i.shift();var x=i.shift(),y=k;l!==u&&(y=fb(k),ja(z,w(l),y));o(function(){b(m,ea,y,e,x)},ea,y,e,x)}i=null}).error(function(a,b,c,d){throw Error("Failed to load template: "+d.url);});return function(a,c,d,e,j){i?(i.push(c),i.push(d),i.push(e),i.push(j)):o(function(){b(m,c,d,e,j)},c,d,e,j)}}function K(a,b){return b.priority-a.priority}function O(a,b,c,d){if(b)throw Error("Multiple directives ["+ +b.name+", "+c.name+"] asking for "+a+" on: "+va(d));}function P(a,b){var c=j(b,!0);c&&a.push({priority:0,compile:S(function(a,b){var d=b.parent(),e=d.data("$binding")||[];e.push(c);x(d.data("$binding",e),"ng-binding");a.$watch(c,function(a){b[0].nodeValue=a})})})}function s(a,b,c,d){var e=j(c,!0);e&&b.push({priority:100,compile:S(function(a,b,c){b=c.$$observers||(c.$$observers={});if(e=j(c[d],!0))c[d]=e(a),(b[d]||(b[d]=[])).$$inter=!0,(c.$$observers&&c.$$observers[d].$$scope||a).$watch(e,function(a){c.$set(d, +a)})})})}function ja(a,b,c){var d=b[0],e=d.parentNode,j,g;if(a){j=0;for(g=a.length;j0){var e=O[0],f=e.text;if(f==a||f==b||f==c||f==d||!a&&!b&&!c&&!d)return e}return!1}function f(b, +c,d,f){return(b=i(b,c,d,f))?(a&&!b.json&&e("is not valid json",b),O.shift(),b):!1}function h(a){f(a)||e("is unexpected, expecting ["+a+"]",i())}function j(a,b){return t(function(c,d){return a(c,d,b)},{constant:b.constant})}function m(a,b,c){return t(function(d,e){return a(d,e)?b(d,e):c(d,e)},{constant:a.constant&&b.constant&&c.constant})}function k(a,b,c){return t(function(d,e){return b(d,e,a,c)},{constant:a.constant&&c.constant})}function l(){for(var a=[];;)if(O.length>0&&!i("}",")",";","]")&&a.push(w()), +!f(";"))return a.length==1?a[0]:function(b,c){for(var d,e=0;e","<=",">="))a=k(a,b.fn,x());return a}function n(){for(var a=v(),b;b=f("*","/","%");)a=k(a,b.fn,v());return a}function v(){var a;return f("+")?A():(a=f("-"))?k($,a.fn,v()):(a=f("!"))?j(a.fn,v()):A()}function A(){var a;if(f("("))a=w(),h(")");else if(f("["))a=G();else if(f("{"))a=D();else{var b=f();(a= +b.fn)||e("not a primary expression",b);if(b.json)a.constant=a.literal=!0}for(var c;b=f("(","[",".");)b.text==="("?(a=s(a,c),c=null):b.text==="["?(c=a,a=ma(a)):b.text==="."?(c=a,a=ja(a)):e("IMPOSSIBLE");return a}function G(){var a=[],b=!0;if(g().text!="]"){do{var c=P();a.push(c);c.constant||(b=!1)}while(f(","))}h("]");return t(function(b,c){for(var d=[],e=0;e1;d++){var e=a.shift(),g=b[e];g||(g={},b[e]=g);b=g}return b[a.shift()]=c}function ib(b,a,c){if(!a)return b;for(var a=a.split("."),d,e=b,g=a.length,i=0;ia)for(b in g++,e)e.hasOwnProperty(b)&&!f.hasOwnProperty(b)&&(x--,delete e[b])}else e!==f&&(e=f,g++);return g}, +function(){b(f,e,c)})},$digest:function(){var a,d,e,i,u=this.$$asyncQueue,o,z,r=b,n,x=[],p,v;g("$digest");do{z=!1;for(n=this;u.length;)try{n.$eval(u.shift())}catch(A){c(A)}do{if(i=n.$$watchers)for(o=i.length;o--;)try{if(a=i[o],(d=a.get(n))!==(e=a.last)&&!(a.eq?ia(d,e):typeof d=="number"&&typeof e=="number"&&isNaN(d)&&isNaN(e)))z=!0,a.last=a.eq?V(d):d,a.fn(d,e===f?d:e,n),r<5&&(p=4-r,x[p]||(x[p]=[]),v=H(a.exp)?"fn: "+(a.exp.name||a.exp.toString()):a.exp,v+="; newVal: "+ha(d)+"; oldVal: "+ha(e),x[p].push(v))}catch(G){c(G)}if(!(i= +n.$$childHead||n!==this&&n.$$nextSibling))for(;n!==this&&!(i=n.$$nextSibling);)n=n.$parent}while(n=i);if(z&&!r--)throw h.$$phase=null,Error(b+" $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: "+ha(x));}while(z||u.length);h.$$phase=null},$destroy:function(){if(!(h==this||this.$$destroyed)){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;if(a.$$childHead==this)a.$$childHead=this.$$nextSibling;if(a.$$childTail==this)a.$$childTail=this.$$prevSibling; +if(this.$$prevSibling)this.$$prevSibling.$$nextSibling=this.$$nextSibling;if(this.$$nextSibling)this.$$nextSibling.$$prevSibling=this.$$prevSibling;this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null}},$eval:function(a,b){return d(a)(this,b)},$evalAsync:function(a){this.$$asyncQueue.push(a)},$apply:function(a){try{return g("$apply"),this.$eval(a)}catch(b){c(b)}finally{h.$$phase=null;try{h.$digest()}catch(d){throw c(d),d;}}},$on:function(a,b){var c=this.$$listeners[a]; +c||(this.$$listeners[a]=c=[]);c.push(b);return function(){c[Ga(c,b)]=null}},$emit:function(a,b){var d=[],e,f=this,g=!1,i={name:a,targetScope:f,stopPropagation:function(){g=!0},preventDefault:function(){i.defaultPrevented=!0},defaultPrevented:!1},h=[i].concat(ka.call(arguments,1)),n,x;do{e=f.$$listeners[a]||d;i.currentScope=f;n=0;for(x=e.length;n7),hasEvent:function(a){if(a=="input"&&Z==9)return!1;if(C(c[a])){var b= +e.createElement("div");c[a]="on"+a in b}return c[a]},csp:e.securityPolicy?e.securityPolicy.isActive:!1,vendorPrefix:g,transitions:h,animations:j}}]}function Zc(){this.$get=S(M)}function Wb(b){var a={},c,d,e;if(!b)return a;n(b.split("\n"),function(b){e=b.indexOf(":");c=I(U(b.substr(0,e)));d=U(b.substr(e+1));c&&(a[c]?a[c]+=", "+d:a[c]=d)});return a}function $c(b,a){var c=ad.exec(b);if(c==null)return!0;var d={protocol:c[2],host:c[4],port:N(c[6])||Oa[c[2]]||null,relativeProtocol:c[2]===p||c[2]===""}, +c=jb.exec(a),c={protocol:c[1],host:c[3],port:N(c[5])||Oa[c[1]]||null};return(d.protocol==c.protocol||d.relativeProtocol)&&d.host==c.host&&(d.port==c.port||d.relativeProtocol&&c.port==Oa[c.protocol])}function Xb(b){var a=L(b)?b:p;return function(c){a||(a=Wb(b));return c?a[I(c)]||null:a}}function Yb(b,a,c){if(H(c))return c(b,a);n(c,function(c){b=c(b,a)});return b}function bd(){var b=/^\s*(\[|\{[^\{])/,a=/[\}\]]\s*$/,c=/^\)\]\}',?\n/,d={"Content-Type":"application/json;charset=utf-8"},e=this.defaults= +{transformResponse:[function(d){E(d)&&(d=d.replace(c,""),b.test(d)&&a.test(d)&&(d=ub(d,!0)));return d}],transformRequest:[function(a){return L(a)&&Ea.apply(a)!=="[object File]"?ha(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},post:d,put:d,patch:d},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN"},g=this.interceptors=[],i=this.responseInterceptors=[];this.$get=["$httpBackend","$browser","$cacheFactory","$rootScope","$q","$injector",function(a,b,c,d,k,l){function u(a){function c(a){var b= +t({},a,{data:Yb(a.data,a.headers,d.transformResponse)});return 200<=a.status&&a.status<300?b:k.reject(b)}var d={transformRequest:e.transformRequest,transformResponse:e.transformResponse},f={};t(d,a);d.headers=f;d.method=oa(d.method);t(f,e.headers.common,e.headers[I(d.method)],a.headers);(a=$c(d.url,b.url())?b.cookies()[d.xsrfCookieName||e.xsrfCookieName]:p)&&(f[d.xsrfHeaderName||e.xsrfHeaderName]=a);var g=[function(a){var b=Yb(a.data,Xb(f),a.transformRequest);C(a.data)&&delete f["Content-Type"];if(C(a.withCredentials)&& +!C(e.withCredentials))a.withCredentials=e.withCredentials;return o(a,b,f).then(c,c)},p],j=k.when(d);for(n(y,function(a){(a.request||a.requestError)&&g.unshift(a.request,a.requestError);(a.response||a.responseError)&&g.push(a.response,a.responseError)});g.length;)var a=g.shift(),i=g.shift(),j=j.then(a,i);j.success=function(a){j.then(function(b){a(b.data,b.status,b.headers,d)});return j};j.error=function(a){j.then(null,function(b){a(b.data,b.status,b.headers,d)});return j};return j}function o(b,c,g){function j(a, +b,c){n&&(200<=a&&a<300?n.put(s,[a,b,Wb(c)]):n.remove(s));i(b,a,c);d.$$phase||d.$apply()}function i(a,c,d){c=Math.max(c,0);(200<=c&&c<300?l.resolve:l.reject)({data:a,status:c,headers:Xb(d),config:b})}function h(){var a=Ga(u.pendingRequests,b);a!==-1&&u.pendingRequests.splice(a,1)}var l=k.defer(),o=l.promise,n,p,s=z(b.url,b.params);u.pendingRequests.push(b);o.then(h,h);if((b.cache||e.cache)&&b.cache!==!1&&b.method=="GET")n=L(b.cache)?b.cache:L(e.cache)?e.cache:r;if(n)if(p=n.get(s))if(p.then)return p.then(h, +h),p;else F(p)?i(p[1],p[0],V(p[2])):i(p,200,{});else n.put(s,o);p||a(b.method,s,c,j,g,b.timeout,b.withCredentials,b.responseType);return o}function z(a,b){if(!b)return a;var c=[];nc(b,function(a,b){a==null||a==p||(F(a)||(a=[a]),n(a,function(a){L(a)&&(a=ha(a));c.push(wa(b)+"="+wa(a))}))});return a+(a.indexOf("?")==-1?"?":"&")+c.join("&")}var r=c("$http"),y=[];n(g,function(a){y.unshift(E(a)?l.get(a):l.invoke(a))});n(i,function(a,b){var c=E(a)?l.get(a):l.invoke(a);y.splice(b,0,{response:function(a){return c(k.when(a))}, +responseError:function(a){return c(k.reject(a))}})});u.pendingRequests=[];(function(a){n(arguments,function(a){u[a]=function(b,c){return u(t(c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){n(arguments,function(a){u[a]=function(b,c,d){return u(t(d||{},{method:a,url:b,data:c}))}})})("post","put");u.defaults=e;return u}]}function cd(){this.$get=["$browser","$window","$document",function(b,a,c){return dd(b,ed,b.defer,a.angular.callbacks,c[0],a.location.protocol.replace(":",""))}]} +function dd(b,a,c,d,e,g){function i(a,b){var c=e.createElement("script"),d=function(){e.body.removeChild(c);b&&b()};c.type="text/javascript";c.src=a;Z?c.onreadystatechange=function(){/loaded|complete/.test(c.readyState)&&d()}:c.onload=c.onerror=d;e.body.appendChild(c);return d}return function(e,h,j,m,k,l,u,o){function z(){p=-1;t&&t();v&&v.abort()}function r(a,d,e,f){var j=(h.match(jb)||["",g])[1];A&&c.cancel(A);t=v=null;d=j=="file"?e?200:404:d;a(d==1223?204:d,e,f);b.$$completeOutstandingRequest(q)} +var p;b.$$incOutstandingRequestCount();h=h||b.url();if(I(e)=="jsonp"){var x="_"+(d.counter++).toString(36);d[x]=function(a){d[x].data=a};var t=i(h.replace("JSON_CALLBACK","angular.callbacks."+x),function(){d[x].data?r(m,200,d[x].data):r(m,p||-2);delete d[x]})}else{var v=new a;v.open(e,h,!0);n(k,function(a,b){a&&v.setRequestHeader(b,a)});v.onreadystatechange=function(){if(v.readyState==4){var a=v.getAllResponseHeaders(),b=["Cache-Control","Content-Language","Content-Type","Expires","Last-Modified", +"Pragma"];a||(a="",n(b,function(b){var c=v.getResponseHeader(b);c&&(a+=b+": "+c+"\n")}));r(m,p||v.status,v.responseType?v.response:v.responseText,a)}};if(u)v.withCredentials=!0;if(o)v.responseType=o;v.send(j||"")}if(l>0)var A=c(z,l);else l&&l.then&&l.then(z)}}function fd(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4", +posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January,February,March,April,May,June,July,August,September,October,November,December".split(","),SHORTMONTH:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(","),DAY:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(","),SHORTDAY:"Sun,Mon,Tue,Wed,Thu,Fri,Sat".split(","),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y", +mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a"},pluralCat:function(b){return b===1?"one":"other"}}}}function gd(){this.$get=["$rootScope","$browser","$q","$exceptionHandler",function(b,a,c,d){function e(e,f,h){var j=c.defer(),m=j.promise,k=B(h)&&!h,f=a.defer(function(){try{j.resolve(e())}catch(a){j.reject(a),d(a)}k||b.$apply()},f),h=function(){delete g[m.$$timeoutId]};m.$$timeoutId=f;g[f]=j;m.then(h,h);return m}var g={};e.cancel=function(b){return b&&b.$$timeoutId in +g?(g[b.$$timeoutId].reject("canceled"),a.defer.cancel(b.$$timeoutId)):!1};return e}]}function Zb(b){function a(a,e){return b.factory(a+c,e)}var c="Filter";this.register=a;this.$get=["$injector",function(a){return function(b){return a.get(b+c)}}];a("currency",$b);a("date",ac);a("filter",hd);a("json",id);a("limitTo",jd);a("lowercase",kd);a("number",bc);a("orderBy",cc);a("uppercase",ld)}function hd(){return function(b,a,c){if(!F(b))return b;var d=[];d.check=function(a){for(var b=0;b-1}}var e=function(a,b){if(typeof b=="string"&&b.charAt(0)==="!")return!e(a,b.substr(1));switch(typeof a){case "boolean":case "number":case "string":return c(a,b);case "object":switch(typeof b){case "object":return c(a,b);default:for(var d in a)if(d.charAt(0)!=="$"&&e(a[d],b))return!0}return!1;case "array":for(d= +0;de+1?i="0":(f=i,j=!0)}if(!j){i=(i.split(ec)[1]||"").length;C(e)&&(e=Math.min(Math.max(a.minFrac,i), +a.maxFrac));var i=Math.pow(10,e),b=Math.round(b*i)/i,b=(""+b).split(ec),i=b[0],b=b[1]||"",j=0,m=a.lgSize,k=a.gSize;if(i.length>=m+k)for(var j=i.length-m,l=0;l0||e>-c)e+=c;e===0&&c==-12&&(e=12);return nb(e,a,d)}}function Qa(b,a){return function(c,d){var e=c["get"+b](),g=oa(a?"SHORT"+b:b);return d[g][e]}}function ac(b){function a(a){var b;if(b=a.match(c)){var a=new Date(0),g=0,i=0,f=b[8]?a.setUTCFullYear:a.setFullYear,h=b[8]?a.setUTCHours:a.setHours;b[9]&&(g=N(b[9]+b[10]),i=N(b[9]+b[11]));f.call(a,N(b[1]),N(b[2])-1,N(b[3]));g=N(b[4]||0)-g;i=N(b[5]||0)-i;f= +N(b[6]||0);b=Math.round(parseFloat("0."+(b[7]||0))*1E3);h.call(a,g,i,f,b)}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,e){var g="",i=[],f,h,e=e||"mediumDate",e=b.DATETIME_FORMATS[e]||e;E(c)&&(c=md.test(c)?N(c):a(c));Ya(c)&&(c=new Date(c));if(!ra(c))return c;for(;e;)(h=nd.exec(e))?(i=i.concat(ka.call(h,1)),e=i.pop()):(i.push(e),e=null);n(i,function(a){f=od[a];g+=f?f(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g, +"").replace(/''/g,"'")});return g}}function id(){return function(b){return ha(b,!0)}}function jd(){return function(b,a){if(!F(b)&&!E(b))return b;a=N(a);if(E(b))return a?a>=0?b.slice(0,a):b.slice(a,b.length):"";var c=[],d,e;a>b.length?a=b.length:a<-b.length&&(a=-b.length);a>0?(d=0,e=a):(d=b.length+a,e=b.length);for(;dl?(d.$setValidity("maxlength",!1),p):(d.$setValidity("maxlength",!0),a)};d.$parsers.push(e);d.$formatters.push(e)}}function ob(b,a){b="ngClass"+b;return aa(function(c,d,e){function g(b){if(a===!0||c.$index%2===a)h&&!ia(b,h)&&i(h),f(b);h=V(b)}function i(a){L(a)&&!F(a)&&(a=Za(a,function(a,b){if(a)return b}));d.removeClass(F(a)?a.join(" "):a)}function f(a){L(a)&&!F(a)&&(a=Za(a, +function(a,b){if(a)return b}));a&&d.addClass(F(a)?a.join(" "):a)}var h=p;c.$watch(e[b],g,!0);e.$observe("class",function(){var a=c.$eval(e[b]);g(a,a)});b!=="ngClass"&&c.$watch("$index",function(d,g){var h=d&1;h!==g&1&&(h===a?f(c.$eval(e[b])):i(c.$eval(e[b])))})})}var I=function(b){return E(b)?b.toLowerCase():b},oa=function(b){return E(b)?b.toUpperCase():b},Z=N((/msie (\d+)/.exec(I(navigator.userAgent))||[])[1]),w,ga,ka=[].slice,Wa=[].push,Ea=Object.prototype.toString,mc=M.angular,Ha=M.angular||(M.angular= +{}),Aa,hb,ba=["0","0","0"];q.$inject=[];qa.$inject=[];hb=Z<9?function(b){b=b.nodeName?b:b[0];return b.scopeName&&b.scopeName!="HTML"?oa(b.scopeName+":"+b.nodeName):b.nodeName}:function(b){return b.nodeName?b.nodeName:b[0].nodeName};var sc=/[A-Z]/g,pd={full:"1.1.5",major:1,minor:1,dot:5,codeName:"triangle-squarification"},Ka=R.cache={},Ja=R.expando="ng-"+(new Date).getTime(),wc=1,gc=M.document.addEventListener?function(b,a,c){b.addEventListener(a,c,!1)}:function(b,a,c){b.attachEvent("on"+a,c)},gb= +M.document.removeEventListener?function(b,a,c){b.removeEventListener(a,c,!1)}:function(b,a,c){b.detachEvent("on"+a,c)},uc=/([\:\-\_]+(.))/g,vc=/^moz([A-Z])/,Ba=R.prototype={ready:function(b){function a(){c||(c=!0,b())}var c=!1;T.readyState==="complete"?setTimeout(a):(this.bind("DOMContentLoaded",a),R(M).bind("load",a))},toString:function(){var b=[];n(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return b>=0?w(this[b]):w(this[this.length+b])},length:0,push:Wa,sort:[].sort, +splice:[].splice},Na={};n("multiple,selected,checked,disabled,readOnly,required,open".split(","),function(b){Na[I(b)]=b});var Gb={};n("input,select,option,textarea,button,form,details".split(","),function(b){Gb[oa(b)]=!0});n({data:Bb,inheritedData:Ma,scope:function(b){return Ma(b,"$scope")},controller:Eb,injector:function(b){return Ma(b,"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:La,css:function(b,a,c){a=Ia(a);if(B(c))b.style[a]=c;else{var d;Z<=8&&(d=b.currentStyle&&b.currentStyle[a], +d===""&&(d="auto"));d=d||b.style[a];Z<=8&&(d=d===""?p:d);return d}},attr:function(b,a,c){var d=I(a);if(Na[d])if(B(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||q).specified?d:p;else if(B(c))b.setAttribute(a,c);else if(b.getAttribute)return b=b.getAttribute(a,2),b===null?p:b},prop:function(b,a,c){if(B(c))b[a]=c;else return b[a]},text:t(Z<9?function(b,a){if(b.nodeType==1){if(C(a))return b.innerText;b.innerText=a}else{if(C(a))return b.nodeValue; +b.nodeValue=a}}:function(b,a){if(C(a))return b.textContent;b.textContent=a},{$dv:""}),val:function(b,a){if(C(a))return b.value;b.value=a},html:function(b,a){if(C(a))return b.innerHTML;for(var c=0,d=b.childNodes;c0||parseFloat(h[a+"Duration"])> +0)g="animation",i=a,j=Math.max(parseInt(h[g+"IterationCount"])||0,parseInt(h[i+"IterationCount"])||0,j);f=Math.max(x(h[g+"Delay"]),x(h[i+"Delay"]));g=Math.max(x(h[g+"Duration"]),x(h[i+"Duration"]));d=Math.max(f+j*g,d)}});e.setTimeout(v,d*1E3)}else v()}function v(){if(!v.run)v.run=!0,o(m,r,p),m.removeClass(w),m.removeClass(K),m.removeData(a)}var A=c.$eval(i.ngAnimate),w=A?L(A)?A[j]:A+"-"+j:"",D=d(w),A=D&&D.setup,$=D&&D.start,D=D&&D.cancel;if(w){var K=w+"-active";r||(r=p?p.parent():m.parent());if(!g.transitions&& +!A&&!$||(r.inheritedData(a)||q).running)k(m,r,p),o(m,r,p);else{var O=m.data(a)||{};O.running&&((D||q)(m),O.done());m.data(a,{running:!0,done:v});m.addClass(w);k(m,r,p);if(m.length==0)return v();var P=(A||q)(m);e.setTimeout(t,1)}}else k(m,r,p),o(m,r,p)}}function m(a,c,d){d?d.after(a):c.append(a)}var k={};k.enter=j("enter",m,q);k.leave=j("leave",q,function(a){a.remove()});k.move=j("move",function(a,c,d){m(a,c,d)},q);k.show=j("show",function(a){a.css("display","")},q);k.hide=j("hide",q,function(a){a.css("display", +"none")});k.animate=function(a,c){j(a,q,q)(c)};return k};i.enabled=function(a){if(arguments.length)c.running=!a;return!c.running};return i}]},Kb="Non-assignable model expression: ";Jb.$inject=["$provide"];var Ic=/^(x[\:\-_]|data[\:\-_])/i,jb=/^([^:]+):\/\/(\w+:{0,1}\w*@)?(\{?[\w\.-]*\}?)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,Pb=/^([^\?#]*)(\?([^#]*))?(#(.*))?$/,Oa={http:80,https:443,ftp:21};Rb.prototype=lb.prototype=Qb.prototype={$$replace:!1,absUrl:Pa("$$absUrl"),url:function(a,c){if(C(a))return this.$$url; +var d=Pb.exec(a);d[1]&&this.path(decodeURIComponent(d[1]));if(d[2]||d[1])this.search(d[3]||"");this.hash(d[5]||"",c);return this},protocol:Pa("$$protocol"),host:Pa("$$host"),port:Pa("$$port"),path:Sb("$$path",function(a){return a.charAt(0)=="/"?a:"/"+a}),search:function(a,c){if(C(a))return this.$$search;B(c)?c===null?delete this.$$search[a]:this.$$search[a]=c:this.$$search=E(a)?vb(a):a;this.$$compose();return this},hash:Sb("$$hash",qa),replace:function(){this.$$replace=!0;return this}};var Da={"null":function(){return null}, +"true":function(){return!0},"false":function(){return!1},undefined:q,"+":function(a,c,d,e){d=d(a,c);e=e(a,c);return B(d)?B(e)?d+e:d:B(e)?e:p},"-":function(a,c,d,e){d=d(a,c);e=e(a,c);return(B(d)?d:0)-(B(e)?e:0)},"*":function(a,c,d,e){return d(a,c)*e(a,c)},"/":function(a,c,d,e){return d(a,c)/e(a,c)},"%":function(a,c,d,e){return d(a,c)%e(a,c)},"^":function(a,c,d,e){return d(a,c)^e(a,c)},"=":q,"===":function(a,c,d,e){return d(a,c)===e(a,c)},"!==":function(a,c,d,e){return d(a,c)!==e(a,c)},"==":function(a, +c,d,e){return d(a,c)==e(a,c)},"!=":function(a,c,d,e){return d(a,c)!=e(a,c)},"<":function(a,c,d,e){return d(a,c)":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a,c,d,e){return d(a,c)<=e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a,c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"&":function(a,c,d,e){return d(a,c)&e(a,c)},"|":function(a,c,d,e){return e(a,c)(a,c,d(a,c))},"!":function(a,c,d){return!d(a,c)}},Qc={n:"\n",f:"\u000c",r:"\r", +t:"\t",v:"\u000b","'":"'",'"':'"'},mb={},ad=/^(([^:]+):)?\/\/(\w+:{0,1}\w*@)?([\w\.-]*)?(:([0-9]+))?(.*)$/,ed=M.XMLHttpRequest||function(){try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(c){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(d){}throw Error("This browser does not support XMLHttpRequest.");};Zb.$inject=["$provide"];$b.$inject=["$locale"];bc.$inject=["$locale"];var ec=".",od={yyyy:Q("FullYear",4),yy:Q("FullYear", +2,0,!0),y:Q("FullYear",1),MMMM:Qa("Month"),MMM:Qa("Month",!0),MM:Q("Month",2,1),M:Q("Month",1,1),dd:Q("Date",2),d:Q("Date",1),HH:Q("Hours",2),H:Q("Hours",1),hh:Q("Hours",2,-12),h:Q("Hours",1,-12),mm:Q("Minutes",2),m:Q("Minutes",1),ss:Q("Seconds",2),s:Q("Seconds",1),sss:Q("Milliseconds",3),EEEE:Qa("Day"),EEE:Qa("Day",!0),a:function(a,c){return a.getHours()<12?c.AMPMS[0]:c.AMPMS[1]},Z:function(a){var a=-1*a.getTimezoneOffset(),c=a>=0?"+":"";c+=nb(Math[a>0?"floor":"ceil"](a/60),2)+nb(Math.abs(a%60), +2);return c}},nd=/((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,md=/^\d+$/;ac.$inject=["$locale"];var kd=S(I),ld=S(oa);cc.$inject=["$parse"];var rd=S({restrict:"E",compile:function(a,c){Z<=8&&(!c.href&&!c.name&&c.$set("href",""),a.append(T.createComment("IE fix")));return function(a,c){c.bind("click",function(a){c.attr("href")||a.preventDefault()})}}}),pb={};n(Na,function(a,c){var d=da("ng-"+c);pb[d]=function(){return{priority:100,compile:function(){return function(a, +g,i){a.$watch(i[d],function(a){i.$set(c,!!a)})}}}}});n(["src","srcset","href"],function(a){var c=da("ng-"+a);pb[c]=function(){return{priority:99,link:function(d,e,g){g.$observe(c,function(c){c&&(g.$set(a,c),Z&&e.prop(a,g[a]))})}}}});var Ta={$addControl:q,$removeControl:q,$setValidity:q,$setDirty:q,$setPristine:q};fc.$inject=["$element","$attrs","$scope"];var Wa=function(a){return["$timeout",function(c){var d={name:"form",restrict:"E",controller:fc,compile:function(){return{pre:function(a,d,i,f){if(!i.action){var h= +function(a){a.preventDefault?a.preventDefault():a.returnValue=!1};gc(d[0],"submit",h);d.bind("$destroy",function(){c(function(){gb(d[0],"submit",h)},0,!1)})}var j=d.parent().controller("form"),m=i.name||i.ngForm;m&&(a[m]=f);j&&d.bind("$destroy",function(){j.$removeControl(f);m&&(a[m]=p);t(f,Ta)})}}}};return a?t(V(d),{restrict:"EAC"}):d}]},sd=Wa(),td=Wa(!0),ud=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,vd=/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/, +wd=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/,hc={text:Va,number:function(a,c,d,e,g,i){Va(a,c,d,e,g,i);e.$parsers.push(function(a){var c=X(a);return c||wd.test(a)?(e.$setValidity("number",!0),a===""?null:c?a:parseFloat(a)):(e.$setValidity("number",!1),p)});e.$formatters.push(function(a){return X(a)?"":""+a});if(d.min){var f=parseFloat(d.min),a=function(a){return!X(a)&&ah?(e.$setValidity("max",!1),p):(e.$setValidity("max",!0),a)};e.$parsers.push(d);e.$formatters.push(d)}e.$formatters.push(function(a){return X(a)||Ya(a)?(e.$setValidity("number",!0),a):(e.$setValidity("number",!1),p)})},url:function(a,c,d,e,g,i){Va(a,c,d,e,g,i);a=function(a){return X(a)||ud.test(a)?(e.$setValidity("url",!0),a):(e.$setValidity("url",!1),p)};e.$formatters.push(a);e.$parsers.push(a)},email:function(a,c,d,e,g,i){Va(a,c,d,e,g,i);a=function(a){return X(a)||vd.test(a)? +(e.$setValidity("email",!0),a):(e.$setValidity("email",!1),p)};e.$formatters.push(a);e.$parsers.push(a)},radio:function(a,c,d,e){C(d.name)&&c.attr("name",Fa());c.bind("click",function(){c[0].checked&&a.$apply(function(){e.$setViewValue(d.value)})});e.$render=function(){c[0].checked=d.value==e.$viewValue};d.$observe("value",e.$render)},checkbox:function(a,c,d,e){var g=d.ngTrueValue,i=d.ngFalseValue;E(g)||(g=!0);E(i)||(i=!1);c.bind("click",function(){a.$apply(function(){e.$setViewValue(c[0].checked)})}); +e.$render=function(){c[0].checked=e.$viewValue};e.$formatters.push(function(a){return a===g});e.$parsers.push(function(a){return a?g:i})},hidden:q,button:q,submit:q,reset:q},ic=["$browser","$sniffer",function(a,c){return{restrict:"E",require:"?ngModel",link:function(d,e,g,i){i&&(hc[I(g.type)]||hc.text)(d,e,g,i,c,a)}}}],Sa="ng-valid",Ra="ng-invalid",pa="ng-pristine",Ua="ng-dirty",xd=["$scope","$exceptionHandler","$attrs","$element","$parse",function(a,c,d,e,g){function i(a,c){c=c?"-"+bb(c,"-"):""; +e.removeClass((a?Ra:Sa)+c).addClass((a?Sa:Ra)+c)}this.$modelValue=this.$viewValue=Number.NaN;this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$name=d.name;var f=g(d.ngModel),h=f.assign;if(!h)throw Error(Kb+d.ngModel+" ("+va(e)+")");this.$render=q;var j=e.inheritedData("$formController")||Ta,m=0,k=this.$error={};e.addClass(pa);i(!0);this.$setValidity=function(a,c){if(k[a]!==!c){if(c){if(k[a]&&m--,!m)i(!0),this.$valid= +!0,this.$invalid=!1}else i(!1),this.$invalid=!0,this.$valid=!1,m++;k[a]=!c;i(c,a);j.$setValidity(a,c,this)}};this.$setPristine=function(){this.$dirty=!1;this.$pristine=!0;e.removeClass(Ua).addClass(pa)};this.$setViewValue=function(d){this.$viewValue=d;if(this.$pristine)this.$dirty=!0,this.$pristine=!1,e.removeClass(pa).addClass(Ua),j.$setDirty();n(this.$parsers,function(a){d=a(d)});if(this.$modelValue!==d)this.$modelValue=d,h(a,d),n(this.$viewChangeListeners,function(a){try{a()}catch(d){c(d)}})}; +var l=this;a.$watch(function(){var c=f(a);if(l.$modelValue!==c){var d=l.$formatters,e=d.length;for(l.$modelValue=c;e--;)c=d[e](c);if(l.$viewValue!==c)l.$viewValue=c,l.$render()}})}],yd=function(){return{require:["ngModel","^?form"],controller:xd,link:function(a,c,d,e){var g=e[0],i=e[1]||Ta;i.$addControl(g);c.bind("$destroy",function(){i.$removeControl(g)})}}},zd=S({require:"ngModel",link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),jc=function(){return{require:"?ngModel", +link:function(a,c,d,e){if(e){d.required=!0;var g=function(a){if(d.required&&(X(a)||a===!1))e.$setValidity("required",!1);else return e.$setValidity("required",!0),a};e.$formatters.push(g);e.$parsers.unshift(g);d.$observe("required",function(){g(e.$viewValue)})}}}},Ad=function(){return{require:"ngModel",link:function(a,c,d,e){var g=(a=/\/(.*)\//.exec(d.ngList))&&RegExp(a[1])||d.ngList||",";e.$parsers.push(function(a){var c=[];a&&n(a.split(g),function(a){a&&c.push(U(a))});return c});e.$formatters.push(function(a){return F(a)? +a.join(", "):p})}}},Bd=/^(true|false|\d+)$/,Cd=function(){return{priority:100,compile:function(a,c){return Bd.test(c.ngValue)?function(a,c,g){g.$set("value",a.$eval(g.ngValue))}:function(a,c,g){a.$watch(g.ngValue,function(a){g.$set("value",a,!1)})}}}},Dd=aa(function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBind);a.$watch(d.ngBind,function(a){c.text(a==p?"":a)})}),Ed=["$interpolate",function(a){return function(c,d,e){c=a(d.attr(e.$attr.ngBindTemplate));d.addClass("ng-binding").data("$binding", +c);e.$observe("ngBindTemplate",function(a){d.text(a)})}}],Fd=[function(){return function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBindHtmlUnsafe);a.$watch(d.ngBindHtmlUnsafe,function(a){c.html(a||"")})}}],Gd=ob("",!0),Hd=ob("Odd",0),Id=ob("Even",1),Jd=aa({compile:function(a,c){c.$set("ngCloak",p);a.removeClass("ng-cloak")}}),Kd=[function(){return{scope:!0,controller:"@"}}],Ld=["$sniffer",function(a){return{priority:1E3,compile:function(){a.csp=!0}}}],kc={};n("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress".split(" "), +function(a){var c=da("ng-"+a);kc[c]=["$parse",function(d){return function(e,g,i){var f=d(i[c]);g.bind(I(a),function(a){e.$apply(function(){f(e,{$event:a})})})}}]});var Md=aa(function(a,c,d){c.bind("submit",function(){a.$apply(d.ngSubmit)})}),Nd=["$animator",function(a){return{transclude:"element",priority:1E3,terminal:!0,restrict:"A",compile:function(c,d,e){return function(c,d,f){var h=a(c,f),j,m;c.$watch(f.ngIf,function(a){j&&(h.leave(j),j=p);m&&(m.$destroy(),m=p);ua(a)&&(m=c.$new(),e(m,function(a){j= +a;h.enter(a,d.parent(),d)}))})}}}}],Od=["$http","$templateCache","$anchorScroll","$compile","$animator",function(a,c,d,e,g){return{restrict:"ECA",terminal:!0,compile:function(i,f){var h=f.ngInclude||f.src,j=f.onload||"",m=f.autoscroll;return function(f,i,n){var o=g(f,n),p=0,r,t=function(){r&&(r.$destroy(),r=null);o.leave(i.contents(),i)};f.$watch(h,function(g){var h=++p;g?(a.get(g,{cache:c}).success(function(a){h===p&&(r&&r.$destroy(),r=f.$new(),o.leave(i.contents(),i),a=w("
").html(a).contents(), +o.enter(a,i),e(a)(r),B(m)&&(!m||f.$eval(m))&&d(),r.$emit("$includeContentLoaded"),f.$eval(j))}).error(function(){h===p&&t()}),f.$emit("$includeContentRequested")):t()})}}}}],Pd=aa({compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),Qd=aa({terminal:!0,priority:1E3}),Rd=["$locale","$interpolate",function(a,c){var d=/{}/g;return{restrict:"EA",link:function(e,g,i){var f=i.count,h=g.attr(i.$attr.when),j=i.offset||0,m=e.$eval(h),k={},l=c.startSymbol(),p=c.endSymbol();n(m,function(a,e){k[e]= +c(a.replace(d,l+f+"-"+j+p))});e.$watch(function(){var c=parseFloat(e.$eval(f));return isNaN(c)?"":(c in m||(c=a.pluralCat(c-j)),k[c](e,g,!0))},function(a){g.text(a)})}}}],Sd=["$parse","$animator",function(a,c){return{transclude:"element",priority:1E3,terminal:!0,compile:function(d,e,g){return function(d,e,h){var j=c(d,h),m=h.ngRepeat,k=m.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),l,p,o,z,r,t={$id:la};if(!k)throw Error("Expected ngRepeat in form of '_item_ in _collection_[ track by _id_]' but got '"+ +m+"'.");h=k[1];o=k[2];(k=k[4])?(l=a(k),p=function(a,c,e){r&&(t[r]=a);t[z]=c;t.$index=e;return l(d,t)}):p=function(a,c){return la(c)};k=h.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);if(!k)throw Error("'item' in 'item in collection' should be identifier or (key, value) but got '"+h+"'.");z=k[3]||k[1];r=k[2];var x={};d.$watchCollection(o,function(a){var c,h,k=e,l,o={},t,q,w,s,B,y,C=[];if(Xa(a))B=a;else{B=[];for(w in a)a.hasOwnProperty(w)&&w.charAt(0)!="$"&&B.push(w);B.sort()}t=B.length;h= +C.length=B.length;for(c=0;c
").html(k).contents();o.enter(k,c);var k=g(k),m=d.current;l=m.scope=a.$new();if(m.controller)f.$scope= +l,f=i(m.controller,f),m.controllerAs&&(l[m.controllerAs]=f),c.children().data("$ngControllerController",f);k(l);l.$emit("$viewContentLoaded");l.$eval(n);e()}else o.leave(c.contents(),c),l&&(l.$destroy(),l=null)}var l,n=m.onload||"",o=f(a,m);a.$on("$routeChangeSuccess",k);k()}}}],ae=["$templateCache",function(a){return{restrict:"E",terminal:!0,compile:function(c,d){d.type=="text/ng-template"&&a.put(d.id,c[0].text)}}}],be=S({terminal:!0}),ce=["$compile","$parse",function(a,c){var d=/^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/, +e={$setViewValue:q};return{restrict:"E",require:["select","?ngModel"],controller:["$element","$scope","$attrs",function(a,c,d){var h=this,j={},m=e,k;h.databound=d.ngModel;h.init=function(a,c,d){m=a;k=d};h.addOption=function(c){j[c]=!0;m.$viewValue==c&&(a.val(c),k.parent()&&k.remove())};h.removeOption=function(a){this.hasOption(a)&&(delete j[a],m.$viewValue==a&&this.renderUnknownOption(a))};h.renderUnknownOption=function(c){c="? "+la(c)+" ?";k.val(c);a.prepend(k);a.val(c);k.prop("selected",!0)};h.hasOption= +function(a){return j.hasOwnProperty(a)};c.$on("$destroy",function(){h.renderUnknownOption=q})}],link:function(e,i,f,h){function j(a,c,d,e){d.$render=function(){var a=d.$viewValue;e.hasOption(a)?(v.parent()&&v.remove(),c.val(a),a===""&&t.prop("selected",!0)):C(a)&&t?c.val(""):e.renderUnknownOption(a)};c.bind("change",function(){a.$apply(function(){v.parent()&&v.remove();d.$setViewValue(c.val())})})}function m(a,c,d){var e;d.$render=function(){var a=new za(d.$viewValue);n(c.find("option"),function(c){c.selected= +B(a.get(c.value))})};a.$watch(function(){ia(e,d.$viewValue)||(e=V(d.$viewValue),d.$render())});c.bind("change",function(){a.$apply(function(){var a=[];n(c.find("option"),function(c){c.selected&&a.push(c.value)});d.$setViewValue(a)})})}function k(e,f,g){function i(){var a={"":[]},c=[""],d,h,q,v,s;q=g.$modelValue;v=u(e)||[];var z=l?qb(v):v,B,y,A;y={};s=!1;var C,D;if(o)if(t&&F(q)){s=new za([]);for(h=0;hA;)v.pop().element.remove()}for(;w.length>y;)w.pop()[0].element.remove()} +var h;if(!(h=q.match(d)))throw Error("Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_ (track by _expr_)?' but got '"+q+"'.");var j=c(h[2]||h[1]),k=h[4]||h[6],l=h[5],m=c(h[3]||""),n=c(h[2]?h[1]:k),u=c(h[7]),t=h[8]?c(h[8]):null,w=[[{element:f,label:""}]];r&&(a(r)(e),r.removeClass("ng-scope"),r.remove());f.html("");f.bind("change",function(){e.$apply(function(){var a,c=u(e)||[],d={},h,i,j,m,q,r;if(o){i=[];m=0;for(r=w.length;m@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none;}ng\\:form{display:block;}'); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbavatar.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/umbavatar.directive.js new file mode 100644 index 0000000000..c92e25b876 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/umbavatar.directive.js @@ -0,0 +1,23 @@ +/** +* @ngdoc directive +* @name umbraco.directives:login +* @restrict E +**/ +function avatarDirective() { + return { + restrict: "E", // restrict to an element + replace: true, // replace the html element with the template + templateUrl: 'views/directives/umb-avatar.html', + scope: { + name: '@', + email: '@', + hash: '@' + }, + link: function(scope, element, attr, ctrl) { + //set the gravatar url + scope.gravatar = "http://www.gravatar.com/avatar/" + scope.hash + "?s=40"; + } + }; +} + +angular.module('umbraco.directives').directive("umbAvatar", avatarDirective); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/leftcolumn.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/umbleftcolumn.directive.js similarity index 57% rename from src/Umbraco.Web.UI.Client/src/common/directives/leftcolumn.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/umbleftcolumn.directive.js index cd5eb92f08..0c74915fa8 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/leftcolumn.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/umbleftcolumn.directive.js @@ -1,18 +1,14 @@ -/** -* @ngdoc directive -* @name umbraco.directive:leftColumn -* @restrict E -**/ -function leftColumnDirective() { - return { - restrict: "E", // restrict to an element - replace: true, // replace the html element with the template - template: '
', - link: function (scope, el, attrs) { - //set the loginViewFile - scope.leftColumnViewFile = "views/directives/umb-leftcolumn.html"; - } - }; -} - -angular.module('umbraco.directives').directive("umbLeftColumn", leftColumnDirective); +/** +* @ngdoc directive +* @name umbraco.directive:leftColumn +* @restrict E +**/ +function leftColumnDirective() { + return { + restrict: "E", // restrict to an element + replace: true, // replace the html element with the template + templateUrl: 'views/directives/umb-leftcolumn.html' + }; +} + +angular.module('umbraco.directives').directive("umbLeftColumn", leftColumnDirective); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/login.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/umblogin.directive.js similarity index 58% rename from src/Umbraco.Web.UI.Client/src/common/directives/login.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/umblogin.directive.js index 0ad3d6818a..c331f321e6 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/login.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/umblogin.directive.js @@ -1,18 +1,14 @@ -/** -* @ngdoc directive -* @name umbraco.directive:login -* @restrict E -**/ -function loginDirective() { - return { - restrict: "E", // restrict to an element - replace: true, // replace the html element with the template - template: '
', - link: function (scope, el, attrs) { - //set the loginViewFile - scope.loginViewFile = "views/directives/umb-login.html"; - } - }; -} - -angular.module('umbraco.directives').directive("umbLogin", loginDirective); +/** +* @ngdoc directive +* @name umbraco.directive:login +* @restrict E +**/ +function loginDirective() { + return { + restrict: "E", // restrict to an element + replace: true, // replace the html element with the template + templateUrl: 'views/directives/umb-login.html' + }; +} + +angular.module('umbraco.directives').directive("umbLogin", loginDirective); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/notifications.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/umbnotifications.directive.js similarity index 57% rename from src/Umbraco.Web.UI.Client/src/common/directives/notifications.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/umbnotifications.directive.js index c439b6bf7e..1a07b75531 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/notifications.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/umbnotifications.directive.js @@ -1,18 +1,14 @@ -/** -* @ngdoc directive -* @name umbraco.directive:notifications -* @restrict E -**/ -function notificationDirective() { - return { - restrict: "E", // restrict to an element - replace: true, // replace the html element with the template - template: '
', - link: function (scope, el, attrs) { - //set the notificationViewFile - scope.notificationViewFile = "views/directives/umb-notifications.html"; - } - }; -} - +/** +* @ngdoc directive +* @name umbraco.directive:notifications +* @restrict E +**/ +function notificationDirective() { + return { + restrict: "E", // restrict to an element + replace: true, // replace the html element with the template + templateUrl: 'views/directives/umb-notifications.html' + }; +} + angular.module('umbraco.directives').directive("umbNotifications", notificationDirective); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/auth.resource.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/auth.resource.js new file mode 100644 index 0000000000..c534742342 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/auth.resource.js @@ -0,0 +1,30 @@ +/** + * @ngdoc factory + * @name umbraco.resources.authResource + * @description Loads in data for authentication + **/ +function authResource($q, $http, umbDataFormatter, umbRequestHelper) { + + var mocked = { + name: "Per Ploug", + email: "test@test.com", + emailHash: "f9879d71855b5ff21e4963273a886bfc", + id: 0, + locale: 'da-DK' + }; + + return { + + /** Logs the user in if the credentials are good */ + performLogin: function (username, password) { + return mocked; + }, + + /** Sends a request to the server to check if the current cookie value is valid for the user */ + isAuthenticated: function () { + return mocked; + } + }; +} + +angular.module('umbraco.mocks.resources').factory('authResource', authResource); diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/user.resource.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/user.resource.js deleted file mode 100644 index 47e0a5de68..0000000000 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/user.resource.js +++ /dev/null @@ -1,42 +0,0 @@ -angular.module('umbraco.mocks.resources') -.factory('userResource', function () { - - var _currentUser,_authenticated = (jQuery.cookie('authed') === "authenticated"); - var _mockedU = { - name: "Per Ploug", - avatar: "assets/img/avatar.jpeg", - id: 0, - authenticated: true, - locale: 'da-DK' - }; - - if(_authenticated){ - _currentUser = _mockedU; - } - - return { - authenticated: _authenticated, - currentUser: _currentUser, - - authenticate: function(login, password){ - _authenticated = true; - _currentUser = _mockedU; - - jQuery.cookie('authed', "authenticated", {expires: 1}); - return _authenticated; - }, - - logout: function(){ - $rootScope.$apply(function() { - _authenticated = false; - jQuery.cookie('authed', null); - _currentUser = undefined; - }); - }, - - getCurrentUser: function(){ - return _currentUser; - } - }; - -}); diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js new file mode 100644 index 0000000000..eeb9aaaabe --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js @@ -0,0 +1,60 @@ +/** + * @ngdoc factory + * @name umbraco.resources.authResource + * @description Loads in data for authentication + **/ +function authResource($q, $http, umbDataFormatter, umbRequestHelper) { + + /** internal method to get the api url */ + function getLoginUrl(username, password) { + return Umbraco.Sys.ServerVariables.authenticationApiBaseUrl + "PostLogin?username=" + username + "&password=" + password; + } + + /** internal method to get the api url */ + function getIsAuthUrl() { + return Umbraco.Sys.ServerVariables.authenticationApiBaseUrl + "GetCurrentUser"; + } + + return { + + /** Logs the user in if the credentials are good */ + performLogin: function (username, password) { + + var deferred = $q.defer(); + //send the data + $http.post(getLoginUrl(username, password)). + success(function (data, status, headers, config) { + deferred.resolve(data); + }). + error(function (data, status, headers, config) { + deferred.reject('Login failed for user ' + username); + }); + + return deferred.promise; + }, + + /** Sends a request to the server to check if the current cookie value is valid for the user */ + isAuthenticated: function () { + + var deferred = $q.defer(); + //send the data + $http.get(getIsAuthUrl()). + success(function (data, status, headers, config) { + deferred.resolve(data); + }). + error(function (data, status, headers, config) { + if (status === 401) { + //if it's unauthorized it just means we are not authenticated so we'll just return null + deferred.resolve(null); + } + else { + deferred.reject('Server call failed for checking authorization'); + } + }); + + return deferred.promise; + } + }; +} + +angular.module('umbraco.resources').factory('authResource', authResource); diff --git a/src/Umbraco.Web.UI.Client/src/common/services/user.service.js b/src/Umbraco.Web.UI.Client/src/common/services/user.service.js index 014d848dce..62435d09e5 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/user.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/user.service.js @@ -1,42 +1,54 @@ angular.module('umbraco.services') -.factory('userService', function () { +.factory('userService', function (authResource, $q) { - var _currentUser,_authenticated = (jQuery.cookie('authed') === "authenticated"); - var _mockedU = { - name: "Per Ploug", - avatar: "assets/img/avatar.jpeg", - id: 0, - authenticated: true, - locale: 'da-DK' - }; + var currentUser = null; - if(_authenticated){ - _currentUser = _mockedU; - } + return { + + /** Returns a promise, sends a request to the server to check if the current cookie is authorized */ + isAuthenticated: function() { + var deferred = $q.defer(); - return { - authenticated: _authenticated, - currentUser: _currentUser, - - authenticate: function(login, password){ - _authenticated = true; - _currentUser = _mockedU; - - jQuery.cookie('authed', "authenticated", {expires: 1}); - return _authenticated; - }, - - logout: function(){ - $rootScope.$apply(function() { - _authenticated = false; - jQuery.cookie('authed', null); - _currentUser = undefined; - }); - }, + $q.when(authResource.isAuthenticated()) + .then(function(data) { + currentUser = data; + //note, this can return null if they are not authenticated + deferred.resolve({ user: data, authenticated: data == null ? false : true }); + }, + function(reason) { + deferred.reject(reason); + }); + + return deferred.promise; + }, + + /** Returns a promise, sends a request to the server to validate the credentials */ + authenticate: function (login, password) { + + var deferred = $q.defer(); + + $q.when(authResource.performLogin(login, password)) + .then(function(data) { + currentUser = data; + deferred.resolve({ user: data, authenticated: true }); + }, + function(reason) { + deferred.reject(reason); + }); + + return deferred.promise; + }, + + logout: function () { + $rootScope.$apply(function () { + currentUser = undefined; + }); + }, + + /** Returns the current user object, if null then calls to authenticated or authenticate must be called */ + getCurrentUser: function () { + return currentUser; + } + }; - getCurrentUser: function(){ - return _currentUser; - } - }; - }); diff --git a/src/Umbraco.Web.UI.Client/src/index.html b/src/Umbraco.Web.UI.Client/src/index.html index 3d8f30376a..380b49d725 100644 --- a/src/Umbraco.Web.UI.Client/src/index.html +++ b/src/Umbraco.Web.UI.Client/src/index.html @@ -6,152 +6,27 @@ Umbraco - + - + -
+
-
-
- +
+
+ {{ui | json}} +
- - - - - - +
+ + -
-
- {{ui | json}} -
-
-
- - -
-
-

Happy {{today}}!, log in below

-
-
- -
-
- - -
-
    -
  • - {{notification.headline}}:{{notification.message}}× -
  • -
-
- - - diff --git a/src/Umbraco.Web.UI.Client/src/less/animations.less b/src/Umbraco.Web.UI.Client/src/less/animations.less index b3d3d6b60d..1dcd9a63eb 100644 --- a/src/Umbraco.Web.UI.Client/src/less/animations.less +++ b/src/Umbraco.Web.UI.Client/src/less/animations.less @@ -1,44 +1,44 @@ // Animations // ------------------------- -.fade-hide-setup, .fade-show-setup { +.fade-hide, .fade-show { -webkit-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.3s; -moz-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.3s; -o-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.3s; transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.3s; } -.fade-hide-setup { +.fade-hide { opacity: 1; } -.fade-hide-setup.fade-hide-start { +.fade-hide.fade-hide-active { opacity: 0; } -.fade-show-setup { +.fade-show { opacity: 0; } -.fade-show-setup.fade-show-start { +.fade-show.fade-show-active { opacity: 1; } -.slide-hide-setup, .slide-show-setup { +.slide-hide, .slide-show { -webkit-transition: all cubic-bezier(0.770, 0.000, 0.175, 1.000) 0.3s; -moz-transition: all cubic-bezier(0.770, 0.000, 0.175, 1.000) 0.3s; -o-transition: all cubic-bezier(0.770, 0.000, 0.175, 1.000) 0.3s; transition: all cubic-bezier(0.770, 0.000, 0.175, 1.000) 0.3s; } -.slide-hide-setup { +.slide-hide { margin-left: 0; } -.slide-hide-setup.slide-hide-start { +.slide-hide.slide-hide-active { margin-left: -100%; } -.slide-show-setup { +.slide-show { margin-left: -100%; } -.slide-show-setup.slide-show-start { +.slide-show.slide-show-active { margin-left: 0; } \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/main.js b/src/Umbraco.Web.UI.Client/src/main.js index 738ea45873..77187671ef 100644 --- a/src/Umbraco.Web.UI.Client/src/main.js +++ b/src/Umbraco.Web.UI.Client/src/main.js @@ -1,6 +1,7 @@ require.config({ waitSeconds: 120, paths: { + app: 'app_dev', jquery: '../lib/jquery/jquery-1.8.2.min', jqueryCookie: '../lib/jquery/jquery.cookie', umbracoExtensions: "../lib/umbraco/extensions", diff --git a/src/Umbraco.Web.UI.Client/src/views/common/application.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/application.controller.js deleted file mode 100644 index 84795dcb70..0000000000 --- a/src/Umbraco.Web.UI.Client/src/views/common/application.controller.js +++ /dev/null @@ -1,145 +0,0 @@ -//Handles the section area of the app -angular.module('umbraco').controller("NavigationController", - function ($scope, navigationService) { - - //load navigation service handlers - $scope.changeSection = navigationService.changeSection; - $scope.showTree = navigationService.showTree; - $scope.hideTree = navigationService.hideTree; - $scope.hideMenu = navigationService.hideMenu; - $scope.showMenu = navigationService.showMenu; - $scope.hideDialog = navigationService.hideDialog; - $scope.hideNavigation = navigationService.hideNavigation; - $scope.ui = navigationService.ui; - - $scope.selectedId = navigationService.currentId; - $scope.sections = navigationService.sections(); - - //events - $scope.$on("treeOptionsClick", function(ev, args){ - $scope.currentNode = args.node; - args.scope = $scope; - navigationService.showMenu(ev, args); - }); - - $scope.openDialog = function(currentNode,action,currentSection){ - navigationService.showDialog({ - scope: $scope, - node: currentNode, - action: action, - section: currentSection}); - }; -}); - - -angular.module('umbraco').controller("SearchController", function ($scope, searchService, $log, navigationService) { - - var currentTerm = ""; - $scope.deActivateSearch = function(){ - currentTerm = ""; - }; - - $scope.performSearch = function (term) { - if(term != undefined && term != currentTerm){ - if(term.length > 3){ - $scope.ui.selectedSearchResult = -1; - navigationService.showSearch(); - currentTerm = term; - $scope.ui.searchResults = searchService.search(term, $scope.currentSection); - }else{ - $scope.ui.searchResults = []; - } - } - }; - - $scope.hideSearch = navigationService.hideSearch; - - $scope.iterateResults = function (direction) { - if(direction == "up" && $scope.ui.selectedSearchResult < $scope.ui.searchResults.length) - $scope.ui.selectedSearchResult++; - else if($scope.ui.selectedSearchResult > 0) - $scope.ui.selectedSearchResult--; - }; - - $scope.selectResult = function () { - navigationService.showMenu($scope.ui.searchResults[$scope.ui.selectedSearchResult], undefined); - }; -}); - - -angular.module('umbraco').controller("DashboardController", function ($scope, $routeParams, scriptLoader) { - $scope.name = $routeParams.section; - - scriptLoader.load(['http://www.google.com/jsapi']) - .then(function(){ - google.load("maps", "3", - { - callback: function () { - - //Google maps is available and all components are ready to use. - var mapOptions = { - zoom: 8, - center: new google.maps.LatLng(-34.397, 150.644), - mapTypeId: google.maps.MapTypeId.ROADMAP - }; - - var mapDiv = document.getElementById('test_map'); - var map = new google.maps.Map(mapDiv, mapOptions); - - }, - other_params: "sensor=false" - }); - }); - -}); - - -//handles authentication and other application.wide services -angular.module('umbraco').controller("MainController", - function ($scope, $routeParams, $rootScope, notificationsService, userService, navigationService) { - - //also be authed for e2e test - var d = new Date(); - var weekday = new Array("Super Sunday", "Manic Monday", "Tremendous Tuesday", "Wonderfull Wednesday", "Thunder Thursday", "Friendly Friday", "Shiny Saturday"); - $scope.today = weekday[d.getDay()]; - - - $scope.signin = function () { - $scope.authenticated = userService.authenticate($scope.login, $scope.password); - - if($scope.authenticated){ - $scope.user = userService.getCurrentUser(); - } - }; - - $scope.signout = function () { - userService.signout(); - $scope.authenticated = false; - }; - - - //subscribes to notifications in the notification service - $scope.notifications = notificationsService.current; - $scope.$watch('notificationsService.current', function (newVal, oldVal, scope) { - if (newVal) { - $scope.notifications = newVal; - } - }); - - $scope.removeNotification = function(index) { - notificationsService.remove(index); - }; - - $scope.closeDialogs = function(event){ - - $rootScope.$emit("closeDialogs"); - - if(navigationService.ui.stickyNavigation && $(event.target).parents(".umb-modalcolumn").size() == 0){ - navigationService.hideNavigation(); - } - }; - - if (userService.authenticated) { - $scope.signin(); - } -}); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dashboard.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dashboard.controller.js new file mode 100644 index 0000000000..2a0b0cc3d0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/common/dashboard.controller.js @@ -0,0 +1,14 @@ +/** + * @ngdoc controller + * @name DashboardController + * @function + * + * @description + * Controls the dashboards of the application + * + */ +function DashboardController($scope, $routeParams) { + $scope.name = $routeParams.section; +} +//register it +angular.module('umbraco').controller("DashboardController", DashboardController); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/main.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/main.controller.js new file mode 100644 index 0000000000..f6b8e95856 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/common/main.controller.js @@ -0,0 +1,82 @@ + +/** + * @ngdoc controller + * @name MainController + * @function + * + * @description + * The main application controller + * + */ +function MainController($scope, $routeParams, $rootScope, $timeout, notificationsService, userService, navigationService) { + //also be authed for e2e test + var d = new Date(); + var weekday = new Array("Super Sunday", "Manic Monday", "Tremendous Tuesday", "Wonderfull Wednesday", "Thunder Thursday", "Friendly Friday", "Shiny Saturday"); + $scope.today = weekday[d.getDay()]; + + + //set default properties + $scope.authenticated = null; //the null is important because we do an explicit bool check on this in the view + $scope.login = ""; + $scope.password = ""; + + /** + * @ngdoc function + * @name signin + * @methodOf MainController + * @function + * + * @description + * signs the user in + */ + $scope.signin = function () { + + userService.authenticate($scope.login, $scope.password) + .then(function (data) { + $scope.authenticated = data.authenticated; + $scope.user = data.user; + }, function (reason) { + alert(reason); + }); + }; + + $scope.signout = function () { + userService.signout(); + $scope.authenticated = false; + }; + + //subscribes to notifications in the notification service + $scope.notifications = notificationsService.current; + $scope.$watch('notificationsService.current', function (newVal, oldVal, scope) { + if (newVal) { + $scope.notifications = newVal; + } + }); + + $scope.removeNotification = function (index) { + notificationsService.remove(index); + }; + + $scope.closeDialogs = function (event) { + + $rootScope.$emit("closeDialogs"); + + if (navigationService.ui.stickyNavigation && $(event.target).parents(".umb-modalcolumn").size() == 0) { + navigationService.hideNavigation(); + } + }; + + //fetch the authorized status + userService.isAuthenticated() + .then(function (data) { + $scope.authenticated = data.authenticated; + $scope.user = data.user; + }, function (reason) { + alert("An error occurred checking authentication."); + $scope.authenticated = false; + $scope.user = null; + }); +} + +//register it +angular.module('umbraco').controller("MainController", MainController); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/common/navigation.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/navigation.controller.js new file mode 100644 index 0000000000..a9ff4cbb72 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/common/navigation.controller.js @@ -0,0 +1,44 @@ + +/** + * @ngdoc controller + * @name NavigationController + * @function + * + * @description + * Handles the section area of the app + * + * @param navigationService {navigationService} A reference to the navigationService + */ +function NavigationController($scope, navigationService) { + //load navigation service handlers + $scope.changeSection = navigationService.changeSection; + $scope.showTree = navigationService.showTree; + $scope.hideTree = navigationService.hideTree; + $scope.hideMenu = navigationService.hideMenu; + $scope.showMenu = navigationService.showMenu; + $scope.hideDialog = navigationService.hideDialog; + $scope.hideNavigation = navigationService.hideNavigation; + $scope.ui = navigationService.ui; + + $scope.selectedId = navigationService.currentId; + $scope.sections = navigationService.sections(); + + //events + $scope.$on("treeOptionsClick", function (ev, args) { + $scope.currentNode = args.node; + args.scope = $scope; + navigationService.showMenu(ev, args); + }); + + $scope.openDialog = function (currentNode, action, currentSection) { + navigationService.showDialog({ + scope: $scope, + node: currentNode, + action: action, + section: currentSection + }); + }; +} + +//register it +angular.module('umbraco').controller("NavigationController", NavigationController); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/common/search.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/search.controller.js new file mode 100644 index 0000000000..54ac10a1ae --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/common/search.controller.js @@ -0,0 +1,43 @@ +/** + * @ngdoc controller + * @name SearchController + * @function + * + * @description + * Controls the search functionality in the site + * + */ +function SearchController($scope, searchService, $log, navigationService) { + var currentTerm = ""; + $scope.deActivateSearch = function () { + currentTerm = ""; + }; + + $scope.performSearch = function (term) { + if (term != undefined && term != currentTerm) { + if (term.length > 3) { + $scope.ui.selectedSearchResult = -1; + navigationService.showSearch(); + currentTerm = term; + $scope.ui.searchResults = searchService.search(term, $scope.currentSection); + } else { + $scope.ui.searchResults = []; + } + } + }; + + $scope.hideSearch = navigationService.hideSearch; + + $scope.iterateResults = function (direction) { + if (direction == "up" && $scope.ui.selectedSearchResult < $scope.ui.searchResults.length) + $scope.ui.selectedSearchResult++; + else if ($scope.ui.selectedSearchResult > 0) + $scope.ui.selectedSearchResult--; + }; + + $scope.selectResult = function () { + navigationService.showMenu($scope.ui.searchResults[$scope.ui.selectedSearchResult], undefined); + }; +} +//register it +angular.module('umbraco').controller("SearchController", SearchController); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/directives/umb-avatar.html b/src/Umbraco.Web.UI.Client/src/views/directives/umb-avatar.html new file mode 100644 index 0000000000..48a4a776ba --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/directives/umb-avatar.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/directives/umb-leftcolumn.html b/src/Umbraco.Web.UI.Client/src/views/directives/umb-leftcolumn.html index 8de56c7978..72c1bd17b1 100644 --- a/src/Umbraco.Web.UI.Client/src/views/directives/umb-leftcolumn.html +++ b/src/Umbraco.Web.UI.Client/src/views/directives/umb-leftcolumn.html @@ -1,17 +1,16 @@
    +
  • - - - +
  • + ng-click="changeSection(section.alias)" + ng-mouseenter="showTree(section.alias)" + prevent-default> {{section.name}}
  • diff --git a/src/Umbraco.Web.UI.Client/src/views/directives/umb-login.html b/src/Umbraco.Web.UI.Client/src/views/directives/umb-login.html index 240ceaa982..8c4f7060ef 100644 --- a/src/Umbraco.Web.UI.Client/src/views/directives/umb-login.html +++ b/src/Umbraco.Web.UI.Client/src/views/directives/umb-login.html @@ -1,9 +1,12 @@ -
    -
    +

    Happy {{today}}!, log in below

    -
    -
    +
    + +
    +
    + +
    -
    \ No newline at end of file +
    diff --git a/src/Umbraco.Web.UI.Client/src/views/directives/umb-notifications.html b/src/Umbraco.Web.UI.Client/src/views/directives/umb-notifications.html index 1f576984b7..57c34cfc48 100644 --- a/src/Umbraco.Web.UI.Client/src/views/directives/umb-notifications.html +++ b/src/Umbraco.Web.UI.Client/src/views/directives/umb-notifications.html @@ -1,4 +1,3 @@ -
    • diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/boolean/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/editor.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/boolean/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/editor.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/code/code.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/code/code.controller.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/code/code.controller.js rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/code/code.controller.js diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/code/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/code/editor.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/code/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/code/editor.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/contentpicker/contentpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/contentpicker/contentpicker.controller.js rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/contentpicker/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/editor.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/contentpicker/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/editor.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/datepicker/bootstrap.datepicker.css b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/bootstrap.datepicker.css similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/datepicker/bootstrap.datepicker.css rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/bootstrap.datepicker.css diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/datepicker/bootstrap.datepicker.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/bootstrap.datepicker.js similarity index 96% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/datepicker/bootstrap.datepicker.js rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/bootstrap.datepicker.js index 3ef33a0d5e..c164bb9721 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/datepicker/bootstrap.datepicker.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/bootstrap.datepicker.js @@ -1,1174 +1,1174 @@ -/* ========================================================= - * bootstrap-datepicker.js - * http://www.eyecon.ro/bootstrap-datepicker - * ========================================================= - * Copyright 2012 Stefan Petre - * Improvements by Andrew Rowls - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================= */ - -!function( $ ) { - - function UTCDate(){ - return new Date(Date.UTC.apply(Date, arguments)); - } - function UTCToday(){ - var today = new Date(); - return UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate()); - } - - // Picker object - - var Datepicker = function(element, options) { - var that = this; - - this.element = $(element); - this.language = options.language||this.element.data('date-language')||"en"; - this.language = this.language in dates ? this.language : this.language.split('-')[0]; //Check if "de-DE" style date is available, if not language should fallback to 2 letter code eg "de" - this.language = this.language in dates ? this.language : "en"; - this.isRTL = dates[this.language].rtl||false; - this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||dates[this.language].format||'mm/dd/yyyy'); - this.isInline = false; - this.isInput = this.element.is('input'); - this.component = this.element.is('.date') ? this.element.find('.add-on, .btn') : false; - this.hasInput = this.component && this.element.find('input').length; - if(this.component && this.component.length === 0) - this.component = false; - - this.forceParse = true; - if ('forceParse' in options) { - this.forceParse = options.forceParse; - } else if ('dateForceParse' in this.element.data()) { - this.forceParse = this.element.data('date-force-parse'); - } - - this.picker = $(DPGlobal.template); - this._buildEvents(); - this._attachEvents(); - - if(this.isInline) { - this.picker.addClass('datepicker-inline').appendTo(this.element); - } else { - this.picker.addClass('datepicker-dropdown dropdown-menu'); - } - if (this.isRTL){ - this.picker.addClass('datepicker-rtl'); - this.picker.find('.prev i, .next i') - .toggleClass('icon-arrow-left icon-arrow-right'); - } - - this.autoclose = false; - if ('autoclose' in options) { - this.autoclose = options.autoclose; - } else if ('dateAutoclose' in this.element.data()) { - this.autoclose = this.element.data('date-autoclose'); - } - - this.keyboardNavigation = true; - if ('keyboardNavigation' in options) { - this.keyboardNavigation = options.keyboardNavigation; - } else if ('dateKeyboardNavigation' in this.element.data()) { - this.keyboardNavigation = this.element.data('date-keyboard-navigation'); - } - - this.viewMode = this.startViewMode = 0; - switch(options.startView || this.element.data('date-start-view')){ - case 2: - case 'decade': - this.viewMode = this.startViewMode = 2; - break; - case 1: - case 'year': - this.viewMode = this.startViewMode = 1; - break; - } - - this.minViewMode = options.minViewMode||this.element.data('date-min-view-mode')||0; - if (typeof this.minViewMode === 'string') { - switch (this.minViewMode) { - case 'months': - this.minViewMode = 1; - break; - case 'years': - this.minViewMode = 2; - break; - default: - this.minViewMode = 0; - break; - } - } - - this.viewMode = this.startViewMode = Math.max(this.startViewMode, this.minViewMode); - - this.todayBtn = (options.todayBtn||this.element.data('date-today-btn')||false); - this.todayHighlight = (options.todayHighlight||this.element.data('date-today-highlight')||false); - - this.calendarWeeks = false; - if ('calendarWeeks' in options) { - this.calendarWeeks = options.calendarWeeks; - } else if ('dateCalendarWeeks' in this.element.data()) { - this.calendarWeeks = this.element.data('date-calendar-weeks'); - } - if (this.calendarWeeks) - this.picker.find('tfoot th.today') - .attr('colspan', function(i, val){ - return parseInt(val) + 1; - }); - - this._allow_update = false; - - this.weekStart = ((options.weekStart||this.element.data('date-weekstart')||dates[this.language].weekStart||0) % 7); - this.weekEnd = ((this.weekStart + 6) % 7); - this.startDate = -Infinity; - this.endDate = Infinity; - this.daysOfWeekDisabled = []; - this.beforeShowDay = options.beforeShowDay || $.noop; - this.setStartDate(options.startDate||this.element.data('date-startdate')); - this.setEndDate(options.endDate||this.element.data('date-enddate')); - this.setDaysOfWeekDisabled(options.daysOfWeekDisabled||this.element.data('date-days-of-week-disabled')); - this.fillDow(); - this.fillMonths(); - this.setRange(options.range); - - this._allow_update = true; - - this.update(); - this.showMode(); - - if(this.isInline) { - this.show(); - } - }; - - Datepicker.prototype = { - constructor: Datepicker, - - _events: [], - _secondaryEvents: [], - _applyEvents: function(evs){ - for (var i=0, el, ev; i this.endDate) { - this.viewDate = new Date(this.endDate); - } else { - this.viewDate = new Date(this.date); - } - this.fill(); - }, - - fillDow: function(){ - var dowCnt = this.weekStart, - html = ''; - if(this.calendarWeeks){ - var cell = ' '; - html += cell; - this.picker.find('.datepicker-days thead tr:first-child').prepend(cell); - } - while (dowCnt < this.weekStart + 7) { - html += ''+dates[this.language].daysMin[(dowCnt++)%7]+''; - } - html += ''; - this.picker.find('.datepicker-days thead').append(html); - }, - - fillMonths: function(){ - var html = '', - i = 0; - while (i < 12) { - html += ''+dates[this.language].monthsShort[i++]+''; - } - this.picker.find('.datepicker-months td').html(html); - }, - - setRange: function(range){ - if (!range || !range.length) - delete this.range; - else - this.range = $.map(range, function(d){ return d.valueOf(); }); - this.fill(); - }, - - getClassNames: function(date){ - var cls = [], - year = this.viewDate.getUTCFullYear(), - month = this.viewDate.getUTCMonth(), - currentDate = this.date.valueOf(), - today = new Date(); - if (date.getUTCFullYear() < year || (date.getUTCFullYear() == year && date.getUTCMonth() < month)) { - cls.push('old'); - } else if (date.getUTCFullYear() > year || (date.getUTCFullYear() == year && date.getUTCMonth() > month)) { - cls.push('new'); - } - // Compare internal UTC date with local today, not UTC today - if (this.todayHighlight && - date.getUTCFullYear() == today.getFullYear() && - date.getUTCMonth() == today.getMonth() && - date.getUTCDate() == today.getDate()) { - cls.push('today'); - } - if (currentDate && date.valueOf() == currentDate) { - cls.push('active'); - } - if (date.valueOf() < this.startDate || date.valueOf() > this.endDate || - $.inArray(date.getUTCDay(), this.daysOfWeekDisabled) !== -1) { - cls.push('disabled'); - } - if (this.range){ - if (date > this.range[0] && date < this.range[this.range.length-1]){ - cls.push('range'); - } - if ($.inArray(date.valueOf(), this.range) != -1){ - cls.push('selected'); - } - } - return cls; - }, - - fill: function() { - var d = new Date(this.viewDate), - year = d.getUTCFullYear(), - month = d.getUTCMonth(), - startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity, - startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity, - endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity, - endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity, - currentDate = this.date && this.date.valueOf(), - tooltip; - this.picker.find('.datepicker-days thead th.datepicker-switch') - .text(dates[this.language].months[month]+' '+year); - this.picker.find('tfoot th.today') - .text(dates[this.language].today) - .toggle(this.todayBtn !== false); - this.updateNavArrows(); - this.fillMonths(); - var prevMonth = UTCDate(year, month-1, 28,0,0,0,0), - day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth()); - prevMonth.setUTCDate(day); - prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7); - var nextMonth = new Date(prevMonth); - nextMonth.setUTCDate(nextMonth.getUTCDate() + 42); - nextMonth = nextMonth.valueOf(); - var html = []; - var clsName; - while(prevMonth.valueOf() < nextMonth) { - if (prevMonth.getUTCDay() == this.weekStart) { - html.push(''); - if(this.calendarWeeks){ - // ISO 8601: First week contains first thursday. - // ISO also states week starts on Monday, but we can be more abstract here. - var - // Start of current week: based on weekstart/current date - ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5), - // Thursday of this week - th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5), - // First Thursday of year, year from thursday - yth = new Date(+(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5), - // Calendar week: ms between thursdays, div ms per day, div 7 days - calWeek = (th - yth) / 864e5 / 7 + 1; - html.push(''+ calWeek +''); - - } - } - clsName = this.getClassNames(prevMonth); - clsName.push('day'); - - var before = this.beforeShowDay(prevMonth); - if (before === undefined) - before = {}; - else if (typeof(before) === 'boolean') - before = {enabled: before}; - else if (typeof(before) === 'string') - before = {classes: before}; - if (before.enabled === false) - clsName.push('disabled'); - if (before.classes) - clsName = clsName.concat(before.classes.split(/\s+/)); - if (before.tooltip) - tooltip = before.tooltip; - - clsName = $.unique(clsName); - html.push(''+prevMonth.getUTCDate() + ''); - if (prevMonth.getUTCDay() == this.weekEnd) { - html.push(''); - } - prevMonth.setUTCDate(prevMonth.getUTCDate()+1); - } - this.picker.find('.datepicker-days tbody').empty().append(html.join('')); - var currentYear = this.date && this.date.getUTCFullYear(); - - var months = this.picker.find('.datepicker-months') - .find('th:eq(1)') - .text(year) - .end() - .find('span').removeClass('active'); - if (currentYear && currentYear == year) { - months.eq(this.date.getUTCMonth()).addClass('active'); - } - if (year < startYear || year > endYear) { - months.addClass('disabled'); - } - if (year == startYear) { - months.slice(0, startMonth).addClass('disabled'); - } - if (year == endYear) { - months.slice(endMonth+1).addClass('disabled'); - } - - html = ''; - year = parseInt(year/10, 10) * 10; - var yearCont = this.picker.find('.datepicker-years') - .find('th:eq(1)') - .text(year + '-' + (year + 9)) - .end() - .find('td'); - year -= 1; - for (var i = -1; i < 11; i++) { - html += ''+year+''; - year += 1; - } - yearCont.html(html); - }, - - updateNavArrows: function() { - if (!this._allow_update) return; - - var d = new Date(this.viewDate), - year = d.getUTCFullYear(), - month = d.getUTCMonth(); - switch (this.viewMode) { - case 0: - if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) { - this.picker.find('.prev').css({visibility: 'hidden'}); - } else { - this.picker.find('.prev').css({visibility: 'visible'}); - } - if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) { - this.picker.find('.next').css({visibility: 'hidden'}); - } else { - this.picker.find('.next').css({visibility: 'visible'}); - } - break; - case 1: - case 2: - if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) { - this.picker.find('.prev').css({visibility: 'hidden'}); - } else { - this.picker.find('.prev').css({visibility: 'visible'}); - } - if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) { - this.picker.find('.next').css({visibility: 'hidden'}); - } else { - this.picker.find('.next').css({visibility: 'visible'}); - } - break; - } - }, - - click: function(e) { - e.preventDefault(); - var target = $(e.target).closest('span, td, th'); - if (target.length == 1) { - switch(target[0].nodeName.toLowerCase()) { - case 'th': - switch(target[0].className) { - case 'datepicker-switch': - this.showMode(1); - break; - case 'prev': - case 'next': - var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1); - switch(this.viewMode){ - case 0: - this.viewDate = this.moveMonth(this.viewDate, dir); - break; - case 1: - case 2: - this.viewDate = this.moveYear(this.viewDate, dir); - break; - } - this.fill(); - break; - case 'today': - var date = new Date(); - date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0); - - this.showMode(-2); - var which = this.todayBtn == 'linked' ? null : 'view'; - this._setDate(date, which); - break; - } - break; - case 'span': - if (!target.is('.disabled')) { - this.viewDate.setUTCDate(1); - if (target.is('.month')) { - var day = 1; - var month = target.parent().find('span').index(target); - var year = this.viewDate.getUTCFullYear(); - this.viewDate.setUTCMonth(month); - this._trigger('changeMonth', this.viewDate); - if ( this.minViewMode == 1 ) { - this._setDate(UTCDate(year, month, day,0,0,0,0)); - } - } else { - var year = parseInt(target.text(), 10)||0; - var day = 1; - var month = 0; - this.viewDate.setUTCFullYear(year); - this._trigger('changeYear', this.viewDate); - if ( this.minViewMode == 2 ) { - this._setDate(UTCDate(year, month, day,0,0,0,0)); - } - } - this.showMode(-1); - this.fill(); - } - break; - case 'td': - if (target.is('.day') && !target.is('.disabled')){ - var day = parseInt(target.text(), 10)||1; - var year = this.viewDate.getUTCFullYear(), - month = this.viewDate.getUTCMonth(); - if (target.is('.old')) { - if (month === 0) { - month = 11; - year -= 1; - } else { - month -= 1; - } - } else if (target.is('.new')) { - if (month == 11) { - month = 0; - year += 1; - } else { - month += 1; - } - } - this._setDate(UTCDate(year, month, day,0,0,0,0)); - } - break; - } - } - }, - - _setDate: function(date, which){ - if (!which || which == 'date') - this.date = date; - if (!which || which == 'view') - this.viewDate = date; - this.fill(); - this.setValue(); - this._trigger('changeDate'); - var element; - if (this.isInput) { - element = this.element; - } else if (this.component){ - element = this.element.find('input'); - } - if (element) { - element.change(); - if (this.autoclose && (!which || which == 'date')) { - this.hide(); - } - } - }, - - moveMonth: function(date, dir){ - if (!dir) return date; - var new_date = new Date(date.valueOf()), - day = new_date.getUTCDate(), - month = new_date.getUTCMonth(), - mag = Math.abs(dir), - new_month, test; - dir = dir > 0 ? 1 : -1; - if (mag == 1){ - test = dir == -1 - // If going back one month, make sure month is not current month - // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02) - ? function(){ return new_date.getUTCMonth() == month; } - // If going forward one month, make sure month is as expected - // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02) - : function(){ return new_date.getUTCMonth() != new_month; }; - new_month = month + dir; - new_date.setUTCMonth(new_month); - // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11 - if (new_month < 0 || new_month > 11) - new_month = (new_month + 12) % 12; - } else { - // For magnitudes >1, move one month at a time... - for (var i=0; i= this.startDate && date <= this.endDate; - }, - - keydown: function(e){ - if (this.picker.is(':not(:visible)')){ - if (e.keyCode == 27) // allow escape to hide and re-show picker - this.show(); - return; - } - var dateChanged = false, - dir, day, month, - newDate, newViewDate; - switch(e.keyCode){ - case 27: // escape - this.hide(); - e.preventDefault(); - break; - case 37: // left - case 39: // right - if (!this.keyboardNavigation) break; - dir = e.keyCode == 37 ? -1 : 1; - if (e.ctrlKey){ - newDate = this.moveYear(this.date, dir); - newViewDate = this.moveYear(this.viewDate, dir); - } else if (e.shiftKey){ - newDate = this.moveMonth(this.date, dir); - newViewDate = this.moveMonth(this.viewDate, dir); - } else { - newDate = new Date(this.date); - newDate.setUTCDate(this.date.getUTCDate() + dir); - newViewDate = new Date(this.viewDate); - newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir); - } - if (this.dateWithinRange(newDate)){ - this.date = newDate; - this.viewDate = newViewDate; - this.setValue(); - this.update(); - e.preventDefault(); - dateChanged = true; - } - break; - case 38: // up - case 40: // down - if (!this.keyboardNavigation) break; - dir = e.keyCode == 38 ? -1 : 1; - if (e.ctrlKey){ - newDate = this.moveYear(this.date, dir); - newViewDate = this.moveYear(this.viewDate, dir); - } else if (e.shiftKey){ - newDate = this.moveMonth(this.date, dir); - newViewDate = this.moveMonth(this.viewDate, dir); - } else { - newDate = new Date(this.date); - newDate.setUTCDate(this.date.getUTCDate() + dir * 7); - newViewDate = new Date(this.viewDate); - newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7); - } - if (this.dateWithinRange(newDate)){ - this.date = newDate; - this.viewDate = newViewDate; - this.setValue(); - this.update(); - e.preventDefault(); - dateChanged = true; - } - break; - case 13: // enter - this.hide(); - e.preventDefault(); - break; - case 9: // tab - this.hide(); - break; - } - if (dateChanged){ - this._trigger('changeDate'); - var element; - if (this.isInput) { - element = this.element; - } else if (this.component){ - element = this.element.find('input'); - } - if (element) { - element.change(); - } - } - }, - - showMode: function(dir) { - if (dir) { - this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir)); - } - /* - vitalets: fixing bug of very special conditions: - jquery 1.7.1 + webkit + show inline datepicker in bootstrap popover. - Method show() does not set display css correctly and datepicker is not shown. - Changed to .css('display', 'block') solve the problem. - See https://github.com/vitalets/x-editable/issues/37 - - In jquery 1.7.2+ everything works fine. - */ - //this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); - this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).css('display', 'block'); - this.updateNavArrows(); - } - }; - - var DateRangePicker = function(element, options){ - this.element = $(element); - this.inputs = $.map(options.inputs, function(i){ return i.jquery ? i[0] : i; }); - delete options.inputs; - - $(this.inputs) - .datepicker(options) - .bind('changeDate', $.proxy(this.dateUpdated, this)); - - this.pickers = $.map(this.inputs, function(i){ return $(i).data('datepicker'); }); - this.updateDates(); - }; - DateRangePicker.prototype = { - updateDates: function(){ - this.dates = $.map(this.pickers, function(i){ return i.date; }); - this.updateRanges(); - }, - updateRanges: function(){ - var range = $.map(this.dates, function(d){ return d.valueOf(); }); - $.each(this.pickers, function(i, p){ - p.setRange(range); - }); - }, - dateUpdated: function(e){ - var dp = $(e.target).data('datepicker'), - new_date = e.date, - i = $.inArray(e.target, this.inputs), - l = this.inputs.length; - if (i == -1) return; - - if (new_date < this.dates[i]){ - // Date being moved earlier/left - while (i>=0 && new_date < this.dates[i]){ - this.pickers[i--].setUTCDate(new_date); - } - } - else if (new_date > this.dates[i]){ - // Date being moved later/right - while (i this.dates[i]){ - this.pickers[i++].setUTCDate(new_date); - } - } - this.updateDates(); - }, - remove: function(){ - $.map(this.pickers, function(p){ p.remove(); }); - delete this.element.data().datepicker; - } - }; - - var old = $.fn.datepicker; - $.fn.datepicker = function ( option ) { - var args = Array.apply(null, arguments); - args.shift(); - return this.each(function () { - var $this = $(this), - data = $this.data('datepicker'), - options = typeof option == 'object' && option; - if (!data) { - if ($this.is('.input-daterange') || options.inputs){ - var opts = { - inputs: options.inputs || $this.find('input').toArray() - }; - $this.data('datepicker', (data = new DateRangePicker(this, $.extend(opts, $.fn.datepicker.defaults,options)))); - } - else{ - $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options)))); - } - } - if (typeof option == 'string' && typeof data[option] == 'function') { - data[option].apply(data, args); - } - }); - }; - - $.fn.datepicker.defaults = { - }; - $.fn.datepicker.Constructor = Datepicker; - var dates = $.fn.datepicker.dates = { - en: { - days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], - daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], - daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], - months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], - monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], - today: "Today" - } - }; - - var DPGlobal = { - modes: [ - { - clsName: 'days', - navFnc: 'Month', - navStep: 1 - }, - { - clsName: 'months', - navFnc: 'FullYear', - navStep: 1 - }, - { - clsName: 'years', - navFnc: 'FullYear', - navStep: 10 - }], - isLeapYear: function (year) { - return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)); - }, - getDaysInMonth: function (year, month) { - return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; - }, - validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g, - nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g, - parseFormat: function(format){ - // IE treats \0 as a string end in inputs (truncating the value), - // so it's a bad format delimiter, anyway - var separators = format.replace(this.validParts, '\0').split('\0'), - parts = format.match(this.validParts); - if (!separators || !separators.length || !parts || parts.length === 0){ - throw new Error("Invalid date format."); - } - return {separators: separators, parts: parts}; - }, - parseDate: function(date, format, language) { - if (date instanceof Date) return date; - if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)) { - var part_re = /([\-+]\d+)([dmwy])/, - parts = date.match(/([\-+]\d+)([dmwy])/g), - part, dir; - date = new Date(); - for (var i=0; i'+ - ''+ - ''+ - ''+ - ''+ - ''+ - '', - contTemplate: '', - footTemplate: '' - }; - DPGlobal.template = '
      '+ - '
      '+ - ''+ - DPGlobal.headTemplate+ - ''+ - DPGlobal.footTemplate+ - '
      '+ - '
      '+ - '
      '+ - ''+ - DPGlobal.headTemplate+ - DPGlobal.contTemplate+ - DPGlobal.footTemplate+ - '
      '+ - '
      '+ - '
      '+ - ''+ - DPGlobal.headTemplate+ - DPGlobal.contTemplate+ - DPGlobal.footTemplate+ - '
      '+ - '
      '+ - '
      '; - - $.fn.datepicker.DPGlobal = DPGlobal; - - - /* DATEPICKER NO CONFLICT - * =================== */ - - $.fn.datepicker.noConflict = function(){ - $.fn.datepicker = old; - return this; - }; - - - /* DATEPICKER DATA-API - * ================== */ - - $(document).on( - 'focus.datepicker.data-api click.datepicker.data-api', - '[data-provide="datepicker"]', - function(e){ - var $this = $(this); - if ($this.data('datepicker')) return; - e.preventDefault(); - // component click requires us to explicitly show it - $this.datepicker('show'); - } - ); - $(function(){ - $('[data-provide="datepicker-inline"]').datepicker(); - }); - -}( window.jQuery ); +/* ========================================================= + * bootstrap-datepicker.js + * http://www.eyecon.ro/bootstrap-datepicker + * ========================================================= + * Copyright 2012 Stefan Petre + * Improvements by Andrew Rowls + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + +!function( $ ) { + + function UTCDate(){ + return new Date(Date.UTC.apply(Date, arguments)); + } + function UTCToday(){ + var today = new Date(); + return UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate()); + } + + // Picker object + + var Datepicker = function(element, options) { + var that = this; + + this.element = $(element); + this.language = options.language||this.element.data('date-language')||"en"; + this.language = this.language in dates ? this.language : this.language.split('-')[0]; //Check if "de-DE" style date is available, if not language should fallback to 2 letter code eg "de" + this.language = this.language in dates ? this.language : "en"; + this.isRTL = dates[this.language].rtl||false; + this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||dates[this.language].format||'mm/dd/yyyy'); + this.isInline = false; + this.isInput = this.element.is('input'); + this.component = this.element.is('.date') ? this.element.find('.add-on, .btn') : false; + this.hasInput = this.component && this.element.find('input').length; + if(this.component && this.component.length === 0) + this.component = false; + + this.forceParse = true; + if ('forceParse' in options) { + this.forceParse = options.forceParse; + } else if ('dateForceParse' in this.element.data()) { + this.forceParse = this.element.data('date-force-parse'); + } + + this.picker = $(DPGlobal.template); + this._buildEvents(); + this._attachEvents(); + + if(this.isInline) { + this.picker.addClass('datepicker-inline').appendTo(this.element); + } else { + this.picker.addClass('datepicker-dropdown dropdown-menu'); + } + if (this.isRTL){ + this.picker.addClass('datepicker-rtl'); + this.picker.find('.prev i, .next i') + .toggleClass('icon-arrow-left icon-arrow-right'); + } + + this.autoclose = false; + if ('autoclose' in options) { + this.autoclose = options.autoclose; + } else if ('dateAutoclose' in this.element.data()) { + this.autoclose = this.element.data('date-autoclose'); + } + + this.keyboardNavigation = true; + if ('keyboardNavigation' in options) { + this.keyboardNavigation = options.keyboardNavigation; + } else if ('dateKeyboardNavigation' in this.element.data()) { + this.keyboardNavigation = this.element.data('date-keyboard-navigation'); + } + + this.viewMode = this.startViewMode = 0; + switch(options.startView || this.element.data('date-start-view')){ + case 2: + case 'decade': + this.viewMode = this.startViewMode = 2; + break; + case 1: + case 'year': + this.viewMode = this.startViewMode = 1; + break; + } + + this.minViewMode = options.minViewMode||this.element.data('date-min-view-mode')||0; + if (typeof this.minViewMode === 'string') { + switch (this.minViewMode) { + case 'months': + this.minViewMode = 1; + break; + case 'years': + this.minViewMode = 2; + break; + default: + this.minViewMode = 0; + break; + } + } + + this.viewMode = this.startViewMode = Math.max(this.startViewMode, this.minViewMode); + + this.todayBtn = (options.todayBtn||this.element.data('date-today-btn')||false); + this.todayHighlight = (options.todayHighlight||this.element.data('date-today-highlight')||false); + + this.calendarWeeks = false; + if ('calendarWeeks' in options) { + this.calendarWeeks = options.calendarWeeks; + } else if ('dateCalendarWeeks' in this.element.data()) { + this.calendarWeeks = this.element.data('date-calendar-weeks'); + } + if (this.calendarWeeks) + this.picker.find('tfoot th.today') + .attr('colspan', function(i, val){ + return parseInt(val) + 1; + }); + + this._allow_update = false; + + this.weekStart = ((options.weekStart||this.element.data('date-weekstart')||dates[this.language].weekStart||0) % 7); + this.weekEnd = ((this.weekStart + 6) % 7); + this.startDate = -Infinity; + this.endDate = Infinity; + this.daysOfWeekDisabled = []; + this.beforeShowDay = options.beforeShowDay || $.noop; + this.setStartDate(options.startDate||this.element.data('date-startdate')); + this.setEndDate(options.endDate||this.element.data('date-enddate')); + this.setDaysOfWeekDisabled(options.daysOfWeekDisabled||this.element.data('date-days-of-week-disabled')); + this.fillDow(); + this.fillMonths(); + this.setRange(options.range); + + this._allow_update = true; + + this.update(); + this.showMode(); + + if(this.isInline) { + this.show(); + } + }; + + Datepicker.prototype = { + constructor: Datepicker, + + _events: [], + _secondaryEvents: [], + _applyEvents: function(evs){ + for (var i=0, el, ev; i this.endDate) { + this.viewDate = new Date(this.endDate); + } else { + this.viewDate = new Date(this.date); + } + this.fill(); + }, + + fillDow: function(){ + var dowCnt = this.weekStart, + html = ''; + if(this.calendarWeeks){ + var cell = ' '; + html += cell; + this.picker.find('.datepicker-days thead tr:first-child').prepend(cell); + } + while (dowCnt < this.weekStart + 7) { + html += ''+dates[this.language].daysMin[(dowCnt++)%7]+''; + } + html += ''; + this.picker.find('.datepicker-days thead').append(html); + }, + + fillMonths: function(){ + var html = '', + i = 0; + while (i < 12) { + html += ''+dates[this.language].monthsShort[i++]+''; + } + this.picker.find('.datepicker-months td').html(html); + }, + + setRange: function(range){ + if (!range || !range.length) + delete this.range; + else + this.range = $.map(range, function(d){ return d.valueOf(); }); + this.fill(); + }, + + getClassNames: function(date){ + var cls = [], + year = this.viewDate.getUTCFullYear(), + month = this.viewDate.getUTCMonth(), + currentDate = this.date.valueOf(), + today = new Date(); + if (date.getUTCFullYear() < year || (date.getUTCFullYear() == year && date.getUTCMonth() < month)) { + cls.push('old'); + } else if (date.getUTCFullYear() > year || (date.getUTCFullYear() == year && date.getUTCMonth() > month)) { + cls.push('new'); + } + // Compare internal UTC date with local today, not UTC today + if (this.todayHighlight && + date.getUTCFullYear() == today.getFullYear() && + date.getUTCMonth() == today.getMonth() && + date.getUTCDate() == today.getDate()) { + cls.push('today'); + } + if (currentDate && date.valueOf() == currentDate) { + cls.push('active'); + } + if (date.valueOf() < this.startDate || date.valueOf() > this.endDate || + $.inArray(date.getUTCDay(), this.daysOfWeekDisabled) !== -1) { + cls.push('disabled'); + } + if (this.range){ + if (date > this.range[0] && date < this.range[this.range.length-1]){ + cls.push('range'); + } + if ($.inArray(date.valueOf(), this.range) != -1){ + cls.push('selected'); + } + } + return cls; + }, + + fill: function() { + var d = new Date(this.viewDate), + year = d.getUTCFullYear(), + month = d.getUTCMonth(), + startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity, + startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity, + endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity, + endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity, + currentDate = this.date && this.date.valueOf(), + tooltip; + this.picker.find('.datepicker-days thead th.datepicker-switch') + .text(dates[this.language].months[month]+' '+year); + this.picker.find('tfoot th.today') + .text(dates[this.language].today) + .toggle(this.todayBtn !== false); + this.updateNavArrows(); + this.fillMonths(); + var prevMonth = UTCDate(year, month-1, 28,0,0,0,0), + day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth()); + prevMonth.setUTCDate(day); + prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7); + var nextMonth = new Date(prevMonth); + nextMonth.setUTCDate(nextMonth.getUTCDate() + 42); + nextMonth = nextMonth.valueOf(); + var html = []; + var clsName; + while(prevMonth.valueOf() < nextMonth) { + if (prevMonth.getUTCDay() == this.weekStart) { + html.push(''); + if(this.calendarWeeks){ + // ISO 8601: First week contains first thursday. + // ISO also states week starts on Monday, but we can be more abstract here. + var + // Start of current week: based on weekstart/current date + ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5), + // Thursday of this week + th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5), + // First Thursday of year, year from thursday + yth = new Date(+(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5), + // Calendar week: ms between thursdays, div ms per day, div 7 days + calWeek = (th - yth) / 864e5 / 7 + 1; + html.push(''+ calWeek +''); + + } + } + clsName = this.getClassNames(prevMonth); + clsName.push('day'); + + var before = this.beforeShowDay(prevMonth); + if (before === undefined) + before = {}; + else if (typeof(before) === 'boolean') + before = {enabled: before}; + else if (typeof(before) === 'string') + before = {classes: before}; + if (before.enabled === false) + clsName.push('disabled'); + if (before.classes) + clsName = clsName.concat(before.classes.split(/\s+/)); + if (before.tooltip) + tooltip = before.tooltip; + + clsName = $.unique(clsName); + html.push(''+prevMonth.getUTCDate() + ''); + if (prevMonth.getUTCDay() == this.weekEnd) { + html.push(''); + } + prevMonth.setUTCDate(prevMonth.getUTCDate()+1); + } + this.picker.find('.datepicker-days tbody').empty().append(html.join('')); + var currentYear = this.date && this.date.getUTCFullYear(); + + var months = this.picker.find('.datepicker-months') + .find('th:eq(1)') + .text(year) + .end() + .find('span').removeClass('active'); + if (currentYear && currentYear == year) { + months.eq(this.date.getUTCMonth()).addClass('active'); + } + if (year < startYear || year > endYear) { + months.addClass('disabled'); + } + if (year == startYear) { + months.slice(0, startMonth).addClass('disabled'); + } + if (year == endYear) { + months.slice(endMonth+1).addClass('disabled'); + } + + html = ''; + year = parseInt(year/10, 10) * 10; + var yearCont = this.picker.find('.datepicker-years') + .find('th:eq(1)') + .text(year + '-' + (year + 9)) + .end() + .find('td'); + year -= 1; + for (var i = -1; i < 11; i++) { + html += ''+year+''; + year += 1; + } + yearCont.html(html); + }, + + updateNavArrows: function() { + if (!this._allow_update) return; + + var d = new Date(this.viewDate), + year = d.getUTCFullYear(), + month = d.getUTCMonth(); + switch (this.viewMode) { + case 0: + if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) { + this.picker.find('.prev').css({visibility: 'hidden'}); + } else { + this.picker.find('.prev').css({visibility: 'visible'}); + } + if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) { + this.picker.find('.next').css({visibility: 'hidden'}); + } else { + this.picker.find('.next').css({visibility: 'visible'}); + } + break; + case 1: + case 2: + if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) { + this.picker.find('.prev').css({visibility: 'hidden'}); + } else { + this.picker.find('.prev').css({visibility: 'visible'}); + } + if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) { + this.picker.find('.next').css({visibility: 'hidden'}); + } else { + this.picker.find('.next').css({visibility: 'visible'}); + } + break; + } + }, + + click: function(e) { + e.preventDefault(); + var target = $(e.target).closest('span, td, th'); + if (target.length == 1) { + switch(target[0].nodeName.toLowerCase()) { + case 'th': + switch(target[0].className) { + case 'datepicker-switch': + this.showMode(1); + break; + case 'prev': + case 'next': + var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1); + switch(this.viewMode){ + case 0: + this.viewDate = this.moveMonth(this.viewDate, dir); + break; + case 1: + case 2: + this.viewDate = this.moveYear(this.viewDate, dir); + break; + } + this.fill(); + break; + case 'today': + var date = new Date(); + date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0); + + this.showMode(-2); + var which = this.todayBtn == 'linked' ? null : 'view'; + this._setDate(date, which); + break; + } + break; + case 'span': + if (!target.is('.disabled')) { + this.viewDate.setUTCDate(1); + if (target.is('.month')) { + var day = 1; + var month = target.parent().find('span').index(target); + var year = this.viewDate.getUTCFullYear(); + this.viewDate.setUTCMonth(month); + this._trigger('changeMonth', this.viewDate); + if ( this.minViewMode == 1 ) { + this._setDate(UTCDate(year, month, day,0,0,0,0)); + } + } else { + var year = parseInt(target.text(), 10)||0; + var day = 1; + var month = 0; + this.viewDate.setUTCFullYear(year); + this._trigger('changeYear', this.viewDate); + if ( this.minViewMode == 2 ) { + this._setDate(UTCDate(year, month, day,0,0,0,0)); + } + } + this.showMode(-1); + this.fill(); + } + break; + case 'td': + if (target.is('.day') && !target.is('.disabled')){ + var day = parseInt(target.text(), 10)||1; + var year = this.viewDate.getUTCFullYear(), + month = this.viewDate.getUTCMonth(); + if (target.is('.old')) { + if (month === 0) { + month = 11; + year -= 1; + } else { + month -= 1; + } + } else if (target.is('.new')) { + if (month == 11) { + month = 0; + year += 1; + } else { + month += 1; + } + } + this._setDate(UTCDate(year, month, day,0,0,0,0)); + } + break; + } + } + }, + + _setDate: function(date, which){ + if (!which || which == 'date') + this.date = date; + if (!which || which == 'view') + this.viewDate = date; + this.fill(); + this.setValue(); + this._trigger('changeDate'); + var element; + if (this.isInput) { + element = this.element; + } else if (this.component){ + element = this.element.find('input'); + } + if (element) { + element.change(); + if (this.autoclose && (!which || which == 'date')) { + this.hide(); + } + } + }, + + moveMonth: function(date, dir){ + if (!dir) return date; + var new_date = new Date(date.valueOf()), + day = new_date.getUTCDate(), + month = new_date.getUTCMonth(), + mag = Math.abs(dir), + new_month, test; + dir = dir > 0 ? 1 : -1; + if (mag == 1){ + test = dir == -1 + // If going back one month, make sure month is not current month + // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02) + ? function(){ return new_date.getUTCMonth() == month; } + // If going forward one month, make sure month is as expected + // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02) + : function(){ return new_date.getUTCMonth() != new_month; }; + new_month = month + dir; + new_date.setUTCMonth(new_month); + // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11 + if (new_month < 0 || new_month > 11) + new_month = (new_month + 12) % 12; + } else { + // For magnitudes >1, move one month at a time... + for (var i=0; i= this.startDate && date <= this.endDate; + }, + + keydown: function(e){ + if (this.picker.is(':not(:visible)')){ + if (e.keyCode == 27) // allow escape to hide and re-show picker + this.show(); + return; + } + var dateChanged = false, + dir, day, month, + newDate, newViewDate; + switch(e.keyCode){ + case 27: // escape + this.hide(); + e.preventDefault(); + break; + case 37: // left + case 39: // right + if (!this.keyboardNavigation) break; + dir = e.keyCode == 37 ? -1 : 1; + if (e.ctrlKey){ + newDate = this.moveYear(this.date, dir); + newViewDate = this.moveYear(this.viewDate, dir); + } else if (e.shiftKey){ + newDate = this.moveMonth(this.date, dir); + newViewDate = this.moveMonth(this.viewDate, dir); + } else { + newDate = new Date(this.date); + newDate.setUTCDate(this.date.getUTCDate() + dir); + newViewDate = new Date(this.viewDate); + newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir); + } + if (this.dateWithinRange(newDate)){ + this.date = newDate; + this.viewDate = newViewDate; + this.setValue(); + this.update(); + e.preventDefault(); + dateChanged = true; + } + break; + case 38: // up + case 40: // down + if (!this.keyboardNavigation) break; + dir = e.keyCode == 38 ? -1 : 1; + if (e.ctrlKey){ + newDate = this.moveYear(this.date, dir); + newViewDate = this.moveYear(this.viewDate, dir); + } else if (e.shiftKey){ + newDate = this.moveMonth(this.date, dir); + newViewDate = this.moveMonth(this.viewDate, dir); + } else { + newDate = new Date(this.date); + newDate.setUTCDate(this.date.getUTCDate() + dir * 7); + newViewDate = new Date(this.viewDate); + newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7); + } + if (this.dateWithinRange(newDate)){ + this.date = newDate; + this.viewDate = newViewDate; + this.setValue(); + this.update(); + e.preventDefault(); + dateChanged = true; + } + break; + case 13: // enter + this.hide(); + e.preventDefault(); + break; + case 9: // tab + this.hide(); + break; + } + if (dateChanged){ + this._trigger('changeDate'); + var element; + if (this.isInput) { + element = this.element; + } else if (this.component){ + element = this.element.find('input'); + } + if (element) { + element.change(); + } + } + }, + + showMode: function(dir) { + if (dir) { + this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir)); + } + /* + vitalets: fixing bug of very special conditions: + jquery 1.7.1 + webkit + show inline datepicker in bootstrap popover. + Method show() does not set display css correctly and datepicker is not shown. + Changed to .css('display', 'block') solve the problem. + See https://github.com/vitalets/x-editable/issues/37 + + In jquery 1.7.2+ everything works fine. + */ + //this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); + this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).css('display', 'block'); + this.updateNavArrows(); + } + }; + + var DateRangePicker = function(element, options){ + this.element = $(element); + this.inputs = $.map(options.inputs, function(i){ return i.jquery ? i[0] : i; }); + delete options.inputs; + + $(this.inputs) + .datepicker(options) + .bind('changeDate', $.proxy(this.dateUpdated, this)); + + this.pickers = $.map(this.inputs, function(i){ return $(i).data('datepicker'); }); + this.updateDates(); + }; + DateRangePicker.prototype = { + updateDates: function(){ + this.dates = $.map(this.pickers, function(i){ return i.date; }); + this.updateRanges(); + }, + updateRanges: function(){ + var range = $.map(this.dates, function(d){ return d.valueOf(); }); + $.each(this.pickers, function(i, p){ + p.setRange(range); + }); + }, + dateUpdated: function(e){ + var dp = $(e.target).data('datepicker'), + new_date = e.date, + i = $.inArray(e.target, this.inputs), + l = this.inputs.length; + if (i == -1) return; + + if (new_date < this.dates[i]){ + // Date being moved earlier/left + while (i>=0 && new_date < this.dates[i]){ + this.pickers[i--].setUTCDate(new_date); + } + } + else if (new_date > this.dates[i]){ + // Date being moved later/right + while (i this.dates[i]){ + this.pickers[i++].setUTCDate(new_date); + } + } + this.updateDates(); + }, + remove: function(){ + $.map(this.pickers, function(p){ p.remove(); }); + delete this.element.data().datepicker; + } + }; + + var old = $.fn.datepicker; + $.fn.datepicker = function ( option ) { + var args = Array.apply(null, arguments); + args.shift(); + return this.each(function () { + var $this = $(this), + data = $this.data('datepicker'), + options = typeof option == 'object' && option; + if (!data) { + if ($this.is('.input-daterange') || options.inputs){ + var opts = { + inputs: options.inputs || $this.find('input').toArray() + }; + $this.data('datepicker', (data = new DateRangePicker(this, $.extend(opts, $.fn.datepicker.defaults,options)))); + } + else{ + $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options)))); + } + } + if (typeof option == 'string' && typeof data[option] == 'function') { + data[option].apply(data, args); + } + }); + }; + + $.fn.datepicker.defaults = { + }; + $.fn.datepicker.Constructor = Datepicker; + var dates = $.fn.datepicker.dates = { + en: { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today" + } + }; + + var DPGlobal = { + modes: [ + { + clsName: 'days', + navFnc: 'Month', + navStep: 1 + }, + { + clsName: 'months', + navFnc: 'FullYear', + navStep: 1 + }, + { + clsName: 'years', + navFnc: 'FullYear', + navStep: 10 + }], + isLeapYear: function (year) { + return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)); + }, + getDaysInMonth: function (year, month) { + return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; + }, + validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g, + nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g, + parseFormat: function(format){ + // IE treats \0 as a string end in inputs (truncating the value), + // so it's a bad format delimiter, anyway + var separators = format.replace(this.validParts, '\0').split('\0'), + parts = format.match(this.validParts); + if (!separators || !separators.length || !parts || parts.length === 0){ + throw new Error("Invalid date format."); + } + return {separators: separators, parts: parts}; + }, + parseDate: function(date, format, language) { + if (date instanceof Date) return date; + if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)) { + var part_re = /([\-+]\d+)([dmwy])/, + parts = date.match(/([\-+]\d+)([dmwy])/g), + part, dir; + date = new Date(); + for (var i=0; i'+ + ''+ + ''+ + ''+ + ''+ + ''+ + '', + contTemplate: '', + footTemplate: '' + }; + DPGlobal.template = '
      '+ + '
      '+ + ''+ + DPGlobal.headTemplate+ + ''+ + DPGlobal.footTemplate+ + '
      '+ + '
      '+ + '
      '+ + ''+ + DPGlobal.headTemplate+ + DPGlobal.contTemplate+ + DPGlobal.footTemplate+ + '
      '+ + '
      '+ + '
      '+ + ''+ + DPGlobal.headTemplate+ + DPGlobal.contTemplate+ + DPGlobal.footTemplate+ + '
      '+ + '
      '+ + '
      '; + + $.fn.datepicker.DPGlobal = DPGlobal; + + + /* DATEPICKER NO CONFLICT + * =================== */ + + $.fn.datepicker.noConflict = function(){ + $.fn.datepicker = old; + return this; + }; + + + /* DATEPICKER DATA-API + * ================== */ + + $(document).on( + 'focus.datepicker.data-api click.datepicker.data-api', + '[data-provide="datepicker"]', + function(e){ + var $this = $(this); + if ($this.data('datepicker')) return; + e.preventDefault(); + // component click requires us to explicitly show it + $this.datepicker('show'); + } + ); + $(function(){ + $('[data-provide="datepicker-inline"]').datepicker(); + }); + +}( window.jQuery ); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/datepicker/datepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js similarity index 97% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/datepicker/datepicker.controller.js rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js index 40cd27d601..95c4740418 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/datepicker/datepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js @@ -1,23 +1,23 @@ -angular.module("umbraco").controller("Umbraco.Editors.DatepickerController", - function ($scope, notificationsService, scriptLoader) { - - scriptLoader.load([ - 'views/propertyeditors/umbraco/datepicker/bootstrap.datepicker.js', - 'css!/belle/views/propertyeditors/umbraco/datepicker/bootstrap.datepicker.css' - ]).then( - function () { - //The Datepicker js and css files are available and all components are ready to use. - - // Get the id of the datepicker button that was clicked - var pickerId = $scope.model.alias; - - // Open the datepicker and add a changeDate eventlistener - $("#" + pickerId).datepicker({ - format: "dd/mm/yyyy", - autoclose: true - }).on("changeDate", function (e) { - // When a date is clicked the date is stored in model.value as a ISO 8601 date - $scope.model.value = e.date.toISOString(); - }); - }); -}); +angular.module("umbraco").controller("Umbraco.Editors.DatepickerController", + function ($scope, notificationsService, scriptLoader) { + + scriptLoader.load([ + 'views/propertyeditors/umbraco/datepicker/bootstrap.datepicker.js', + 'css!/belle/views/propertyeditors/umbraco/datepicker/bootstrap.datepicker.css' + ]).then( + function () { + //The Datepicker js and css files are available and all components are ready to use. + + // Get the id of the datepicker button that was clicked + var pickerId = $scope.model.alias; + + // Open the datepicker and add a changeDate eventlistener + $("#" + pickerId).datepicker({ + format: "dd/mm/yyyy", + autoclose: true + }).on("changeDate", function (e) { + // When a date is clicked the date is stored in model.value as a ISO 8601 date + $scope.model.value = e.date.toISOString(); + }); + }); +}); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/datepicker/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/editor.html similarity index 98% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/datepicker/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/editor.html index 3d88778673..7fd2d73376 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/datepicker/editor.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/editor.html @@ -1,6 +1,6 @@ -
      -
      - - -
      +
      +
      + + +
      \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/dropdown/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdown/editor.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/dropdown/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdown/editor.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/fileupload/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/editor.html similarity index 98% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/fileupload/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/editor.html index da66fa108d..23ece7dfe6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/fileupload/editor.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/editor.html @@ -1,2 +1,2 @@ - + \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/googlemaps/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/googlemaps/editor.html similarity index 98% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/googlemaps/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/googlemaps/editor.html index 9effacac9e..6c5f0b74d7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/googlemaps/editor.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/googlemaps/editor.html @@ -1,3 +1,3 @@ -
      -
      +
      +
      \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/googlemaps/googlemaps.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/googlemaps/googlemaps.controller.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/googlemaps/googlemaps.controller.js rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/googlemaps/googlemaps.controller.js diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/grid/css/iframe.css b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/css/iframe.css similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/grid/css/iframe.css rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/css/iframe.css diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/grid/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editor.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/grid/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editor.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/grid/grid.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/grid/grid.controller.js rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/grid/iframe.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/iframe.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/grid/iframe.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/iframe.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/grid/js/iframe.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/js/iframe.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/grid/js/iframe.js rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/js/iframe.js diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/listview/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/editor.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/listview/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/editor.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/listview/listview.controller.js rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/mediapicker/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/editor.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/mediapicker/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/editor.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/mediapicker/mediapicker.controller.js rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/readonlyvalue/readonlyvalue.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/readonlyvalue/readonlyvalue.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/readonlyvalue/readonlyvalue.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/readonlyvalue/readonlyvalue.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/rte/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/editor.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/rte/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/editor.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/rte/rte.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/rte/rte.controller.js rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/sample/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/sample/editor.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/sample/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/sample/editor.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/sampletwo/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/sampletwo/editor.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/sampletwo/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/sampletwo/editor.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/tags/bootstrap-tags.custom.css b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/bootstrap-tags.custom.css similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/tags/bootstrap-tags.custom.css rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/bootstrap-tags.custom.css diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/tags/bootstrap-tags.custom.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/bootstrap-tags.custom.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/tags/bootstrap-tags.custom.js rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/bootstrap-tags.custom.js diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/tags/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/editor.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/tags/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/editor.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/tags/tags.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/tags/tags.controller.js rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/test/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/test/editor.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/test/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/test/editor.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/test/embeddedcontent.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/test/embeddedcontent.controller.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/test/embeddedcontent.controller.js rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/test/embeddedcontent.controller.js diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/textarea/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textarea/editor.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/textarea/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/textarea/editor.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/textstring/editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textstring/editor.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/views/propertyeditors/umbraco/textstring/editor.html rename to src/Umbraco.Web.UI.Client/src/views/propertyeditors/textstring/editor.html diff --git a/src/Umbraco.Web.UI/App_Plugins/Umbraco/Package.manifest b/src/Umbraco.Web.UI/App_Plugins/Umbraco/Package.manifest index cd70184bff..a8225a9eb3 100644 --- a/src/Umbraco.Web.UI/App_Plugins/Umbraco/Package.manifest +++ b/src/Umbraco.Web.UI/App_Plugins/Umbraco/Package.manifest @@ -1,12 +1,5 @@ { - propertyEditors: [ - { - id: "ec15c1e5-9d90-422a-aa52-4f7622c63bea", - name: "Textstring", - editor: { - view: "~/umbraco/Views/propertyeditors/umbraco/textstring/editor.html" - } - }, + propertyEditors: [ { id: "67db8357-ef57-493e-91ac-936d305e0f2a", name: "Textarea", diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 6ba2067bf3..5b2ebea8f6 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -2566,8 +2566,8 @@ - REM CD /D $(SolutionDir)Umbraco.Web.UI.Client\ -REM grunt.cmd build + CD /D $(SolutionDir)Umbraco.Web.UI.Client\ +grunt.cmd build xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\amd64\*.* "$(TargetDir)amd64\" /Y /F /E /D xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\" /Y /F /E /D diff --git a/src/Umbraco.Web.UI/install/Default.aspx.cs b/src/Umbraco.Web.UI/install/Default.aspx.cs index a53429c2b6..b9b848aab6 100644 --- a/src/Umbraco.Web.UI/install/Default.aspx.cs +++ b/src/Umbraco.Web.UI/install/Default.aspx.cs @@ -63,7 +63,7 @@ namespace Umbraco.Web.UI.Install // It's not considered an upgrade if the ConfigurationStatus is missing or empty. if (string.IsNullOrWhiteSpace(GlobalSettings.ConfigurationStatus) == false) { - var result = Security.ValidateCurrentUser(new HttpContextWrapper(Context)); + var result = Security.ValidateCurrentUser(); if (result == ValidateRequestAttempt.FailedTimedOut || result == ValidateRequestAttempt.FailedNoPrivileges) { diff --git a/src/Umbraco.Web.UI/umbraco/Views/Default.cshtml b/src/Umbraco.Web.UI/umbraco/Views/Default.cshtml index 15f1a0796f..24b4234b21 100644 --- a/src/Umbraco.Web.UI/umbraco/Views/Default.cshtml +++ b/src/Umbraco.Web.UI/umbraco/Views/Default.cshtml @@ -51,7 +51,7 @@ -
      +
      diff --git a/src/Umbraco.Web.UI/umbraco/Views/directives/umb-leftcolumn.html b/src/Umbraco.Web.UI/umbraco/Views/directives/umb-leftcolumn.html index 8de56c7978..72c1bd17b1 100644 --- a/src/Umbraco.Web.UI/umbraco/Views/directives/umb-leftcolumn.html +++ b/src/Umbraco.Web.UI/umbraco/Views/directives/umb-leftcolumn.html @@ -1,17 +1,16 @@
        +
      • - - - +
      • + ng-click="changeSection(section.alias)" + ng-mouseenter="showTree(section.alias)" + prevent-default> {{section.name}}
      • diff --git a/src/Umbraco.Web.UI/umbraco/Views/directives/umb-login.html b/src/Umbraco.Web.UI/umbraco/Views/directives/umb-login.html deleted file mode 100644 index 240ceaa982..0000000000 --- a/src/Umbraco.Web.UI/umbraco/Views/directives/umb-login.html +++ /dev/null @@ -1,9 +0,0 @@ - -
        -
        -

        Happy {{today}}!, log in below

        -
        -
        - -
        -
        \ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/Views/directives/umb-notifications.html b/src/Umbraco.Web.UI/umbraco/Views/directives/umb-notifications.html deleted file mode 100644 index 1f576984b7..0000000000 --- a/src/Umbraco.Web.UI/umbraco/Views/directives/umb-notifications.html +++ /dev/null @@ -1,8 +0,0 @@ - -
        -
          -
        • - {{notification.headline}}:{{notification.message}}× -
        • -
        -
        \ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 69824636d8..b24a83de35 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -639,6 +639,7 @@ To manage your website, simply open the umbraco back office and start adding con Upgrade instructions There's an upgrade available for this package. You can download it directly from the umbraco package repository. Package version + Package version history View package website diff --git a/src/Umbraco.Web.UI/umbraco/developer/Packages/installedPackage.aspx b/src/Umbraco.Web.UI/umbraco/developer/Packages/installedPackage.aspx index b1c2d9c8ec..d624d4c7f9 100644 --- a/src/Umbraco.Web.UI/umbraco/developer/Packages/installedPackage.aspx +++ b/src/Umbraco.Web.UI/umbraco/developer/Packages/installedPackage.aspx @@ -56,7 +56,17 @@ - + + + + + + + + +
        diff --git a/src/Umbraco.Web.UI/umbraco/js/app_dev.js b/src/Umbraco.Web.UI/umbraco/js/app_dev.js new file mode 100644 index 0000000000..d0a45d9af8 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/js/app_dev.js @@ -0,0 +1,16 @@ +/*! umbraco - v0.0.1-SNAPSHOT - 2013-06-18 + * http://umbraco.github.io/Belle + * Copyright (c) 2013 Per Ploug, Anders Stenteberg & Shannon Deminick; + * Licensed MIT + */ +'use strict'; +define(['angular'], function (angular) { +var app = angular.module('umbraco', [ + 'umbraco.filters', + 'umbraco.directives', + 'umbraco.mocks.resources', + 'umbraco.services' +]); + +return app; +}); \ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/settings/stylesheet/editstylesheet.aspx b/src/Umbraco.Web.UI/umbraco/settings/stylesheet/editstylesheet.aspx index e380ac0c17..5ed8dd435e 100644 --- a/src/Umbraco.Web.UI/umbraco/settings/stylesheet/editstylesheet.aspx +++ b/src/Umbraco.Web.UI/umbraco/settings/stylesheet/editstylesheet.aspx @@ -25,10 +25,11 @@ } }); editor.init(); - }); //bind save shortcut UmbClientMgr.appActions().bindSaveShortCut(); + }); + })(jQuery); diff --git a/src/Umbraco.Web.UI/umbraco_client/FolderBrowser/Js/folderbrowser.js b/src/Umbraco.Web.UI/umbraco_client/FolderBrowser/Js/folderbrowser.js index a8132ae7c7..438a04344a 100644 --- a/src/Umbraco.Web.UI/umbraco_client/FolderBrowser/Js/folderbrowser.js +++ b/src/Umbraco.Web.UI/umbraco_client/FolderBrowser/Js/folderbrowser.js @@ -178,7 +178,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls"); var overlay = $("
        " + "
        " + instructions + - "
        " + + "" + "" + "" + "" + diff --git a/src/Umbraco.Web.UI/web.Template.Debug.config b/src/Umbraco.Web.UI/web.Template.Debug.config index 937cee3f3a..de074b944e 100644 --- a/src/Umbraco.Web.UI/web.Template.Debug.config +++ b/src/Umbraco.Web.UI/web.Template.Debug.config @@ -28,8 +28,8 @@ + - diff --git a/src/Umbraco.Web.UI/web.Template.config b/src/Umbraco.Web.UI/web.Template.config index 924381560b..19dceac49d 100644 --- a/src/Umbraco.Web.UI/web.Template.config +++ b/src/Umbraco.Web.UI/web.Template.config @@ -45,7 +45,6 @@ - @@ -167,13 +166,6 @@ - - - - - - - @@ -290,4 +282,4 @@ - \ No newline at end of file + diff --git a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs index 0f529b8840..435fb9c7ef 100644 --- a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs +++ b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs @@ -402,7 +402,7 @@ namespace Umbraco.Web.Cache { DistributedCache.Instance.RefreshUserCache(sender.UserId); } - if (sender.Nodes.Any()) + if (sender.NodeIds.Any()) { DistributedCache.Instance.RefreshAllUserCache(); } diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs new file mode 100644 index 0000000000..509c39f8ef --- /dev/null +++ b/src/Umbraco.Web/Editors/AuthenticationController.cs @@ -0,0 +1,65 @@ +using System.Net; +using System.Web; +using System.Web.Http; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Models.Mapping; +using Umbraco.Web.Mvc; +using Umbraco.Web.Security; +using Umbraco.Web.WebApi; + +namespace Umbraco.Web.Editors +{ + /// + /// The API controller used for editing content + /// + [PluginController("UmbracoApi")] + [ValidationFilter] + public class AuthenticationController : UmbracoApiController + { + private readonly UserModelMapper _userModelMapper; + + public AuthenticationController() + : this(new UserModelMapper()) + { + } + + internal AuthenticationController(UserModelMapper userModelMapper) + { + _userModelMapper = userModelMapper; + } + + /// + /// Simply checks if the current user's cookie is valid and if so returns the user object associated + /// + /// + public UserDetail GetCurrentUser() + { + var attempt = UmbracoContext.Security.AuthorizeRequest(); + if (attempt == ValidateRequestAttempt.Success) + { + var user = + Services.UserService.GetUserById( + UmbracoContext.Security.GetUserId(UmbracoContext.Security.UmbracoUserContextId)); + return _userModelMapper.ToUserDetail(user); + } + throw new HttpResponseException(HttpStatusCode.Unauthorized); + } + + public UserDetail PostLogin(string username, string password) + { + if (UmbracoContext.Security.ValidateBackOfficeCredentials(username, password)) + { + var user = Services.UserService.GetUserByUserName(username); + //TODO: Clean up the int cast! + UmbracoContext.Security.PerformLogin((int)user.Id); + return _userModelMapper.ToUserDetail(user); + } + throw new HttpResponseException(HttpStatusCode.Unauthorized); + } + + //public HttpResponseMessage PostLogout() + //{ + + //} + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index f9a6ba49b1..2ea7b641b1 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -51,7 +51,8 @@ namespace Umbraco.Web.Editors {"mediaApiBaseUrl", Url.GetUmbracoApiService("GetRootMedia").TrimEnd("GetRootMedia")}, {"treeApplicationApiBaseUrl", Url.GetUmbracoApiService("GetTreeData").TrimEnd("GetTreeData")}, {"contentTypeApiBaseUrl", Url.GetUmbracoApiService("GetAllowedChildren").TrimEnd("GetAllowedChildren")}, - {"mediaTypeApiBaseUrl", Url.GetUmbracoApiService("GetAllowedChildren").TrimEnd("GetAllowedChildren")} + {"mediaTypeApiBaseUrl", Url.GetUmbracoApiService("GetAllowedChildren").TrimEnd("GetAllowedChildren")}, + {"authenticationApiBaseUrl", Url.GetUmbracoApiService("PostLogin").TrimEnd("PostLogin")} }; return JavaScript(ServerVariablesParser.Parse(d)); diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 911bcf2792..6fa7f5c454 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -7,10 +7,12 @@ using System.Web.Http.ModelBinding; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; +using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Models.Mapping; using Umbraco.Web.Mvc; +using Umbraco.Web.Security; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Binders; using Umbraco.Web.WebApi.Filters; @@ -30,7 +32,7 @@ namespace Umbraco.Web.Editors /// Constructor /// public ContentController() - : this(UmbracoContext.Current, new ContentModelMapper(UmbracoContext.Current.Application, new ProfileModelMapper())) + : this(UmbracoContext.Current, new ContentModelMapper(UmbracoContext.Current.Application, new UserModelMapper())) { } diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 512045f90c..d1ea8b5e64 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -38,7 +38,7 @@ namespace Umbraco.Web.Editors /// Constructor /// public MediaController() - : this(UmbracoContext.Current, new MediaModelMapper(UmbracoContext.Current.Application, new ProfileModelMapper())) + : this(UmbracoContext.Current, new MediaModelMapper(UmbracoContext.Current.Application, new UserModelMapper())) { } diff --git a/src/Umbraco.Web/Models/ContentEditing/UserDetail.cs b/src/Umbraco.Web/Models/ContentEditing/UserDetail.cs new file mode 100644 index 0000000000..70aaa0cd77 --- /dev/null +++ b/src/Umbraco.Web/Models/ContentEditing/UserDetail.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; + +namespace Umbraco.Web.Models.ContentEditing +{ + [DataContract(Name = "user", Namespace = "")] + public class UserDetail : UserBasic + { + [DataMember(Name = "email", IsRequired = true)] + [Required] + public string Email { get; set; } + + [DataMember(Name = "locale", IsRequired = true)] + [Required] + public string Language { get; set; } + + /// + /// The MD5 lowercase hash of the email which can be used by gravatar + /// + [DataMember(Name = "emailHash")] + public string EmailHash { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Models/Mapping/BaseContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/BaseContentModelMapper.cs index 14512eb02e..add6c5a15b 100644 --- a/src/Umbraco.Web/Models/Mapping/BaseContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/BaseContentModelMapper.cs @@ -12,12 +12,12 @@ namespace Umbraco.Web.Models.Mapping internal class BaseContentModelMapper { protected ApplicationContext ApplicationContext { get; private set; } - protected ProfileModelMapper ProfileMapper { get; private set; } + protected UserModelMapper UserMapper { get; private set; } - public BaseContentModelMapper(ApplicationContext applicationContext, ProfileModelMapper profileMapper) + public BaseContentModelMapper(ApplicationContext applicationContext, UserModelMapper userMapper) { ApplicationContext = applicationContext; - ProfileMapper = profileMapper; + UserMapper = userMapper; } protected ContentItemDto ToContentItemDtoBase(IContentBase content) @@ -86,7 +86,7 @@ namespace Umbraco.Web.Models.Mapping var result = new TContent { Id = content.Id, - Owner = ProfileMapper.ToBasicUser(content.GetCreatorProfile()), + Owner = UserMapper.ToUserBasic(content.GetCreatorProfile()), ParentId = content.ParentId, UpdateDate = content.UpdateDate, diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs index e3cb35608e..eb3cda0ed2 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs @@ -10,8 +10,8 @@ namespace Umbraco.Web.Models.Mapping internal class ContentModelMapper : BaseContentModelMapper { - public ContentModelMapper(ApplicationContext applicationContext, ProfileModelMapper profileMapper) - : base(applicationContext, profileMapper) + public ContentModelMapper(ApplicationContext applicationContext, UserModelMapper userMapper) + : base(applicationContext, userMapper) { } @@ -21,7 +21,7 @@ namespace Umbraco.Web.Models.Mapping //NOTE: we don't need this for the dto and it's an extra lookup //result.ContentTypeAlias = content.ContentType.Alias; //result.Icon = content.ContentType.Icon; - //result.Updator = ProfileMapper.ToBasicUser(content.GetWriterProfile()); + //result.Updator = userMapper.ToUserBasic(content.GetWriterProfile()); return result; } @@ -30,7 +30,7 @@ namespace Umbraco.Web.Models.Mapping var result = base.ToContentItemSimpleBase(content); result.ContentTypeAlias = content.ContentType.Alias; result.Icon = content.ContentType.Icon; - result.Updator = ProfileMapper.ToBasicUser(content.GetWriterProfile()); + result.Updator = UserMapper.ToUserBasic(content.GetWriterProfile()); return result; } @@ -42,7 +42,7 @@ namespace Umbraco.Web.Models.Mapping var result = CreateContent(content, (display, originalContent) => { //fill in the rest - display.Updator = ProfileMapper.ToBasicUser(content.GetWriterProfile()); + display.Updator = UserMapper.ToUserBasic(content.GetWriterProfile()); display.ContentTypeAlias = content.ContentType.Alias; display.Icon = content.ContentType.Icon; diff --git a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs index a97c249315..7b079664fd 100644 --- a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs @@ -12,8 +12,8 @@ namespace Umbraco.Web.Models.Mapping { internal class MediaModelMapper : BaseContentModelMapper { - public MediaModelMapper(ApplicationContext applicationContext, ProfileModelMapper profileMapper) - : base(applicationContext, profileMapper) + public MediaModelMapper(ApplicationContext applicationContext, UserModelMapper userMapper) + : base(applicationContext, userMapper) { } @@ -23,7 +23,7 @@ namespace Umbraco.Web.Models.Mapping //NOTE: we don't need this for the dto and it's an extra lookup //result.ContentTypeAlias = content.ContentType.Alias; //result.Icon = content.ContentType.Icon; - //result.Updator = ProfileMapper.ToBasicUser(content.GetWriterProfile()); + //result.Updator = userMapper.ToUserBasic(content.GetWriterProfile()); return result; } diff --git a/src/Umbraco.Web/Models/Mapping/ProfileModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ProfileModelMapper.cs deleted file mode 100644 index af4f6a96e0..0000000000 --- a/src/Umbraco.Web/Models/Mapping/ProfileModelMapper.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using Umbraco.Core; -using Umbraco.Core.Models.Membership; -using Umbraco.Web.Models.ContentEditing; - -namespace Umbraco.Web.Models.Mapping -{ - internal class ProfileModelMapper - { - public UserBasic ToBasicUser(IProfile profile) - { - var user = new UserBasic - { - Name = profile.Name - }; - var result = profile.Id.TryConvertTo(); - if (result.Success == false) - { - throw new InvalidOperationException("Cannot convert the profile to a " + typeof(UserBasic).Name + " object since the id is not an integer"); - } - user.UserId = result.Result; - return user; - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs b/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs new file mode 100644 index 0000000000..bada4d4e12 --- /dev/null +++ b/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs @@ -0,0 +1,46 @@ +using System; +using AutoMapper; +using Umbraco.Core; +using Umbraco.Core.Models.Membership; +using Umbraco.Web.Models.ContentEditing; + +namespace Umbraco.Web.Models.Mapping +{ + internal class UserModelMapper + { + /// + /// Configures the automapper mappings + /// + internal static void Configure() + { + Mapper.CreateMap() + .ForMember(detail => detail.UserId, opt => opt.MapFrom(user => GetIntId(user.Id))) + .ForMember( + detail => detail.EmailHash, + opt => opt.MapFrom(user => user.Email.ToLowerInvariant().Trim().ToMd5())); + Mapper.CreateMap() + .ForMember(detail => detail.UserId, opt => opt.MapFrom(profile => GetIntId(profile.Id))); + } + + private static int GetIntId(object id) + { + var result = id.TryConvertTo(); + if (result.Success == false) + { + throw new InvalidOperationException( + "Cannot convert the profile to a " + typeof(UserDetail).Name + " object since the id is not an integer"); + } + return result.Result; + } + + public UserDetail ToUserDetail(IUser user) + { + return Mapper.Map(user); + } + + public UserBasic ToUserBasic(IProfile profile) + { + return Mapper.Map(profile); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs b/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs index 98a845a2f0..833fe92906 100644 --- a/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs +++ b/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs @@ -90,12 +90,14 @@ namespace Umbraco.Web.Mvc controllerPluginRoute.DataTokens.Add("UseNamespaceFallback", false); //constraints: only match controllers ending with 'controllerSuffixName' and only match this controller's ID for this route + if (controllerSuffixName.IsNullOrWhiteSpace() == false) + { controllerPluginRoute.Constraints = new RouteValueDictionary( new Dictionary { {"controller", @"(\w+)" + controllerSuffixName} }); - + } //match this area controllerPluginRoute.DataTokens.Add("area", area.AreaName); diff --git a/src/Umbraco.Web/Mvc/BackOfficeArea.cs b/src/Umbraco.Web/Mvc/BackOfficeArea.cs index 8dc1e9727e..b91cbba9b2 100644 --- a/src/Umbraco.Web/Mvc/BackOfficeArea.cs +++ b/src/Umbraco.Web/Mvc/BackOfficeArea.cs @@ -1,4 +1,4 @@ -using System.Web.Mvc; +using System.Web.Mvc; using Umbraco.Core.Configuration; using Umbraco.Web.Editors; using Umbraco.Web.Install; diff --git a/src/Umbraco.Web/Mvc/FilteredControllerFactoriesResolver.cs b/src/Umbraco.Web/Mvc/FilteredControllerFactoriesResolver.cs index c6c0e5d109..e4fadf7c4b 100644 --- a/src/Umbraco.Web/Mvc/FilteredControllerFactoriesResolver.cs +++ b/src/Umbraco.Web/Mvc/FilteredControllerFactoriesResolver.cs @@ -7,7 +7,7 @@ namespace Umbraco.Web.Mvc /// /// A resolver for storing IFilteredControllerFactories /// - internal sealed class FilteredControllerFactoriesResolver : ManyObjectsResolverBase + public sealed class FilteredControllerFactoriesResolver : ManyObjectsResolverBase { /// /// Constructor diff --git a/src/Umbraco.Web/Mvc/RenderMvcController.cs b/src/Umbraco.Web/Mvc/RenderMvcController.cs index 0f26610070..4615937e6b 100644 --- a/src/Umbraco.Web/Mvc/RenderMvcController.cs +++ b/src/Umbraco.Web/Mvc/RenderMvcController.cs @@ -73,13 +73,13 @@ namespace Umbraco.Web.Mvc /// protected bool EnsurePhsyicalViewExists(string template) { - if (!System.IO.File.Exists( - Path.Combine(Server.MapPath(Constants.ViewLocation), template + ".cshtml"))) - { - LogHelper.Warn("No physical template file was found for template " + template); - return false; - } - return true; + var result = ViewEngines.Engines.FindView(ControllerContext, template, null); + if(result.View == null) + { + LogHelper.Warn("No physical template file was found for template " + template); + return false; + } + return true; } /// diff --git a/src/Umbraco.Web/PropertyEditors/TextStringPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/TextStringPropertyEditor.cs new file mode 100644 index 0000000000..599a40557c --- /dev/null +++ b/src/Umbraco.Web/PropertyEditors/TextStringPropertyEditor.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Umbraco.Core; +using Umbraco.Core.PropertyEditors; + +namespace Umbraco.Web.PropertyEditors +{ + + [PropertyEditor(Constants.PropertyEditors.Textbox, "Textstring", "textstring")] + public class TextStringPropertyEditor : PropertyEditor + { + } + +} diff --git a/src/Umbraco.Web/Security/WebSecurity.cs b/src/Umbraco.Web/Security/WebSecurity.cs index 972644ff49..5b21afb8e5 100644 --- a/src/Umbraco.Web/Security/WebSecurity.cs +++ b/src/Umbraco.Web/Security/WebSecurity.cs @@ -19,6 +19,13 @@ namespace Umbraco.Web.Security /// public class WebSecurity { + private readonly HttpContextBase _httpContext; + + public WebSecurity(HttpContextBase httpContext) + { + _httpContext = httpContext; + } + /// /// Returns true or false if the currently logged in member is authorized based on the parameters provided /// @@ -288,10 +295,9 @@ namespace Umbraco.Web.Security /// /// Validates the current user /// - /// /// set to true if you want exceptions to be thrown if failed /// - internal ValidateRequestAttempt ValidateCurrentUser(HttpContextBase httpContext, bool throwExceptions = false) + internal ValidateRequestAttempt ValidateCurrentUser(bool throwExceptions = false) { if (UmbracoUserContextId != "") { @@ -303,7 +309,7 @@ namespace Umbraco.Web.Security var user = User.GetUser(uid); // Check for console access - if (user.Disabled || (user.NoConsole && GlobalSettings.RequestIsInUmbracoApplication(httpContext) && GlobalSettings.RequestIsLiveEditRedirector(httpContext) == false)) + if (user.Disabled || (user.NoConsole && GlobalSettings.RequestIsInUmbracoApplication(_httpContext) && GlobalSettings.RequestIsLiveEditRedirector(_httpContext) == false)) { if (throwExceptions) throw new ArgumentException("You have no priviledges to the umbraco console. Please contact your administrator"); return ValidateRequestAttempt.FailedNoPrivileges; @@ -321,18 +327,17 @@ namespace Umbraco.Web.Security /// /// Authorizes the full request, checks for SSL and validates the current user /// - /// /// set to true if you want exceptions to be thrown if failed /// - internal ValidateRequestAttempt AuthorizeRequest(HttpContextBase httpContext, bool throwExceptions = false) + internal ValidateRequestAttempt AuthorizeRequest(bool throwExceptions = false) { // check for secure connection - if (GlobalSettings.UseSSL && httpContext.Request.IsSecureConnection == false) + if (GlobalSettings.UseSSL && _httpContext.Request.IsSecureConnection == false) { if (throwExceptions) throw new UserAuthorizationException("This installation requires a secure connection (via SSL). Please update the URL to include https://"); return ValidateRequestAttempt.FailedNoSsl; } - return ValidateCurrentUser(httpContext, throwExceptions); + return ValidateCurrentUser(throwExceptions); } /// diff --git a/src/Umbraco.Web/Standalone/ServiceContextManager.cs b/src/Umbraco.Web/Standalone/ServiceContextManager.cs index badd77d21b..aa53b586ee 100644 --- a/src/Umbraco.Web/Standalone/ServiceContextManager.cs +++ b/src/Umbraco.Web/Standalone/ServiceContextManager.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using Umbraco.Core; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; @@ -15,12 +16,15 @@ namespace Umbraco.Web.Standalone private ServiceContext _serviceContext; private readonly StandaloneApplication _application; - public ServiceContextManager(string connectionString, string providerName) + public ServiceContextManager(string connectionString, string providerName, string baseDirectory) { _connectionString = connectionString; _providerName = providerName; - _application = StandaloneApplication.GetApplication(); + Trace.WriteLine("Current AppDomain: " + AppDomain.CurrentDomain.FriendlyName); + Trace.WriteLine("Current AppDomain: " + AppDomain.CurrentDomain.BaseDirectory); + + _application = StandaloneApplication.GetApplication(baseDirectory); _application.Start(); } diff --git a/src/Umbraco.Web/Standalone/StandaloneApplication.cs b/src/Umbraco.Web/Standalone/StandaloneApplication.cs index a1fd0249a7..cdaf8718c1 100644 --- a/src/Umbraco.Web/Standalone/StandaloneApplication.cs +++ b/src/Umbraco.Web/Standalone/StandaloneApplication.cs @@ -14,7 +14,10 @@ namespace Umbraco.Web.Standalone /// /// Initializes a new instance of the class. /// - protected StandaloneApplication(){ } + protected StandaloneApplication(string baseDirectory) + { + _baseDirectory = baseDirectory; + } /// /// Provides the application boot manager. @@ -22,23 +25,24 @@ namespace Umbraco.Web.Standalone /// An application boot manager. protected override IBootManager GetBootManager() { - return new StandaloneBootManager(this, _handlersToAdd, _handlersToRemove); + return new StandaloneBootManager(this, _handlersToAdd, _handlersToRemove, _baseDirectory); } #region Application private static StandaloneApplication _application; + private readonly string _baseDirectory; private static bool _started; private static readonly object AppLock = new object(); /// /// Gets the instance of the standalone Umbraco application. /// - public static StandaloneApplication GetApplication() + public static StandaloneApplication GetApplication(string baseDirectory) { lock (AppLock) { - return _application ?? (_application = new StandaloneApplication()); + return _application ?? (_application = new StandaloneApplication(baseDirectory)); } } diff --git a/src/Umbraco.Web/Standalone/StandaloneBootManager.cs b/src/Umbraco.Web/Standalone/StandaloneBootManager.cs index 1215ab89a7..cf2e8f7c11 100644 --- a/src/Umbraco.Web/Standalone/StandaloneBootManager.cs +++ b/src/Umbraco.Web/Standalone/StandaloneBootManager.cs @@ -20,12 +20,16 @@ namespace Umbraco.Web.Standalone private readonly IEnumerable _handlersToAdd; private readonly IEnumerable _handlersToRemove; + private readonly string _baseDirectory; - public StandaloneBootManager(UmbracoApplicationBase umbracoApplication, IEnumerable handlersToAdd, IEnumerable handlersToRemove) + public StandaloneBootManager(UmbracoApplicationBase umbracoApplication, IEnumerable handlersToAdd, IEnumerable handlersToRemove, string baseDirectory) : base(umbracoApplication) { _handlersToAdd = handlersToAdd; _handlersToRemove = handlersToRemove; + _baseDirectory = baseDirectory; + + base.InitializeApplicationRootPath(_baseDirectory); // this is only here to ensure references to the assemblies needed for // the DataTypesResolver otherwise they won't be loaded into the AppDomain. @@ -63,7 +67,7 @@ namespace Umbraco.Web.Standalone typeof (ContentFinderByPageIdQuery), typeof (ContentFinderByNiceUrl), typeof (ContentFinderByIdPath), - typeof(ContentFinderByNotFoundHandlers) + typeof (ContentFinderByNotFoundHandlers) ); // fixme - what else? diff --git a/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs b/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs index 3979415dc7..4210fc1e3e 100644 --- a/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs +++ b/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs @@ -28,7 +28,7 @@ namespace Umbraco.Web.UI.Pages try { - Security.ValidateCurrentUser(new HttpContextWrapper(Context), true); + Security.ValidateCurrentUser(true); _hasValidated = true; if (!Security.ValidateUserApp(CurrentApp)) @@ -80,7 +80,7 @@ namespace Umbraco.Web.UI.Pages //throw exceptions if not valid (true) if (!_hasValidated) { - Security.ValidateCurrentUser(new HttpContextWrapper(Context), true); + Security.ValidateCurrentUser(true); _hasValidated = true; } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 2e965d2279..93c9649890 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -95,6 +95,9 @@ {07fbc26b-2927-4a22-8d96-d644c667fecc} UmbracoExamine + + ..\packages\AutoMapper.2.2.1\lib\net40\AutoMapper.dll + False ..\packages\ClientDependency.1.7.0.2\lib\ClientDependency.Core.dll @@ -292,6 +295,7 @@ + @@ -301,13 +305,14 @@ + - - + + @@ -402,6 +407,7 @@ + diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index b5c3f1339f..7542764abb 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -135,7 +135,7 @@ namespace Umbraco.Web HttpContext = httpContext; Application = applicationContext; - Security = new WebSecurity(); + Security = new WebSecurity(HttpContext); ContentCache = publishedCaches.CreateContextualContentCache(this); MediaCache = publishedCaches.CreateContextualMediaCache(this); diff --git a/src/Umbraco.Web/WebApi/Binders/ContentItemBinder.cs b/src/Umbraco.Web/WebApi/Binders/ContentItemBinder.cs index 9856c42304..d50c1849f1 100644 --- a/src/Umbraco.Web/WebApi/Binders/ContentItemBinder.cs +++ b/src/Umbraco.Web/WebApi/Binders/ContentItemBinder.cs @@ -20,7 +20,7 @@ namespace Umbraco.Web.WebApi.Binders /// Constructor /// public ContentItemBinder() - : this(ApplicationContext.Current, new ContentModelMapper(ApplicationContext.Current, new ProfileModelMapper())) + : this(ApplicationContext.Current, new ContentModelMapper(ApplicationContext.Current, new UserModelMapper())) { } diff --git a/src/Umbraco.Web/WebApi/Binders/MediaItemBinder.cs b/src/Umbraco.Web/WebApi/Binders/MediaItemBinder.cs index 2dfd0ae131..02d12ba8b0 100644 --- a/src/Umbraco.Web/WebApi/Binders/MediaItemBinder.cs +++ b/src/Umbraco.Web/WebApi/Binders/MediaItemBinder.cs @@ -20,7 +20,7 @@ namespace Umbraco.Web.WebApi.Binders /// Constructor /// public MediaItemBinder() - : this(ApplicationContext.Current, new MediaModelMapper(ApplicationContext.Current, new ProfileModelMapper())) + : this(ApplicationContext.Current, new MediaModelMapper(ApplicationContext.Current, new UserModelMapper())) { } diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs index 6a1e778f67..a166b96702 100644 --- a/src/Umbraco.Web/WebBootManager.cs +++ b/src/Umbraco.Web/WebBootManager.cs @@ -20,6 +20,7 @@ using Umbraco.Web.Editors; using Umbraco.Web.Media; using Umbraco.Web.Media.ThumbnailProviders; using Umbraco.Web.Models; +using Umbraco.Web.Models.Mapping; using Umbraco.Web.Mvc; using Umbraco.Web.PropertyEditors; using Umbraco.Web.PublishedCache; @@ -40,10 +41,10 @@ namespace Umbraco.Web { private readonly bool _isForTesting; - public WebBootManager(UmbracoApplicationBase umbracoApplication) + public WebBootManager(UmbracoApplicationBase umbracoApplication) : this(umbracoApplication, false) { - + } /// @@ -51,10 +52,10 @@ namespace Umbraco.Web /// /// /// - internal WebBootManager(UmbracoApplicationBase umbracoApplication, bool isForTesting) + internal WebBootManager(UmbracoApplicationBase umbracoApplication, bool isForTesting) : base(umbracoApplication) { - _isForTesting = isForTesting; + _isForTesting = isForTesting; } /// @@ -62,7 +63,7 @@ namespace Umbraco.Web /// /// public override IBootManager Initialize() - { + { base.Initialize(); // Backwards compatibility - set the path and URL type for ClientDependency 1.5.1 [LK] @@ -111,6 +112,15 @@ namespace Umbraco.Web ProfilerResolver.Current.SetProfiler(new WebProfiler()); } + /// + /// Configure the model mappers + /// + protected override void InitializeModelMappers() + { + base.InitializeModelMappers(); + UserModelMapper.Configure(); + } + /// /// Adds custom types to the ApplicationEventsResolver /// @@ -210,8 +220,8 @@ namespace Umbraco.Web var meta = PluginController.GetMetadata(controller); var route = RouteTable.Routes.MapHttpRoute( string.Format("umbraco-{0}-{1}", "api", meta.ControllerName), - umbracoPath + "/Api/" + meta.ControllerName + "/{action}/{id}",//url to match - new { controller = meta.ControllerName, id = UrlParameter.Optional }); + umbracoPath + "/Api/" + meta.ControllerName + "/{action}/{id}", //url to match + new {controller = meta.ControllerName, id = UrlParameter.Optional}); //web api routes don't set the data tokens object if (route.DataTokens == null) { @@ -221,7 +231,6 @@ namespace Umbraco.Web route.DataTokens.Add("UseNamespaceFallback", false); //Don't look anywhere else except this namespace! route.DataTokens.Add("umbraco", "api"); //ensure the umbraco token is set } - private void RouteLocalSurfaceController(Type controller, string umbracoPath) { var meta = PluginController.GetMetadata(controller); diff --git a/src/Umbraco.Web/WebServices/UmbracoAuthorizedHttpHandler.cs b/src/Umbraco.Web/WebServices/UmbracoAuthorizedHttpHandler.cs index a16b37a468..f83120f0d0 100644 --- a/src/Umbraco.Web/WebServices/UmbracoAuthorizedHttpHandler.cs +++ b/src/Umbraco.Web/WebServices/UmbracoAuthorizedHttpHandler.cs @@ -97,7 +97,7 @@ namespace Umbraco.Web.WebServices /// protected bool AuthorizeRequest(bool throwExceptions = false) { - var result = Security.AuthorizeRequest(new HttpContextWrapper(HttpContext.Current), throwExceptions); + var result = Security.AuthorizeRequest(throwExceptions); return result == ValidateRequestAttempt.Success; } @@ -110,7 +110,7 @@ namespace Umbraco.Web.WebServices { if (!_hasValidated) { - Security.ValidateCurrentUser(new HttpContextWrapper(HttpContext.Current)); + Security.ValidateCurrentUser(); _hasValidated = true; } return Security.CurrentUser; diff --git a/src/Umbraco.Web/WebServices/UmbracoAuthorizedWebService.cs b/src/Umbraco.Web/WebServices/UmbracoAuthorizedWebService.cs index a532936e77..d59ed125d8 100644 --- a/src/Umbraco.Web/WebServices/UmbracoAuthorizedWebService.cs +++ b/src/Umbraco.Web/WebServices/UmbracoAuthorizedWebService.cs @@ -102,7 +102,7 @@ namespace Umbraco.Web.WebServices /// protected bool AuthorizeRequest(bool throwExceptions = false) { - var result = Security.AuthorizeRequest(new HttpContextWrapper(Context), throwExceptions); + var result = Security.AuthorizeRequest(throwExceptions); return result == ValidateRequestAttempt.Success; } @@ -115,7 +115,7 @@ namespace Umbraco.Web.WebServices { if (!_hasValidated) { - Security.ValidateCurrentUser(new HttpContextWrapper(Context)); + Security.ValidateCurrentUser(); _hasValidated = true; } return Security.CurrentUser; diff --git a/src/Umbraco.Web/packages.config b/src/Umbraco.Web/packages.config index d370ef28d5..9f5ddf7b61 100644 --- a/src/Umbraco.Web/packages.config +++ b/src/Umbraco.Web/packages.config @@ -1,5 +1,6 @@  + diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadPackages.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadPackages.cs index 7d19a48e8b..cbdc3f0a90 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadPackages.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadPackages.cs @@ -1,29 +1,14 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.Data; -using System.IO; +using System.Linq; using System.Text; using System.Web; using System.Xml; -using System.Configuration; -using umbraco.BasePages; -using umbraco.BusinessLogic; using umbraco.businesslogic; -using umbraco.cms.businesslogic; -using umbraco.cms.businesslogic.cache; -using umbraco.cms.businesslogic.contentitem; -using umbraco.cms.businesslogic.datatype; -using umbraco.cms.businesslogic.language; -using umbraco.cms.businesslogic.media; -using umbraco.cms.businesslogic.member; -using umbraco.cms.businesslogic.property; -using umbraco.cms.businesslogic.web; -using umbraco.interfaces; -using umbraco.DataLayer; -using umbraco.BusinessLogic.Utils; +using umbraco.cms.businesslogic.packager; using umbraco.cms.presentation.Trees; using Umbraco.Core; +using umbraco.interfaces; namespace umbraco { @@ -64,18 +49,24 @@ namespace umbraco switch (m_packageType) { case "installed": - foreach (cms.businesslogic.packager.InstalledPackage p in cms.businesslogic.packager.InstalledPackage.GetAllInstalledPackages()) + Version v; + // Display the unique packages, ordered by the latest version number. [LK 2013-06-10] + var uniquePackages = InstalledPackage.GetAllInstalledPackages() + .OrderByDescending(x => Version.TryParse(x.Data.Version, out v) ? v : new Version()) + .GroupBy(x => x.Data.Name) + .Select(x => x.First()) + .OrderBy(x => x.Data.Id); + foreach (var p in uniquePackages) { - XmlTreeNode xNode = XmlTreeNode.Create(this); - xNode.NodeID = PACKAGE_TREE_PREFIX + p.Data.Id.ToString(); + var xNode = XmlTreeNode.Create(this); + xNode.NodeID = string.Concat(PACKAGE_TREE_PREFIX, p.Data.Id); xNode.Text = p.Data.Name; - xNode.Action = "javascript:openInstalledPackage('" + p.Data.Id.ToString() + "');"; + xNode.Action = string.Format("javascript:openInstalledPackage('{0}');", p.Data.Id); xNode.Icon = "package.gif"; xNode.OpenIcon = "package.gif"; xNode.NodeType = "createdPackageInstance"; xNode.Menu = null; tree.Add(xNode); - } break; diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installedPackage.aspx b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installedPackage.aspx index b1c2d9c8ec..990e4394ae 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installedPackage.aspx +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installedPackage.aspx @@ -56,7 +56,17 @@ - + + + + + + + + +
        diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installedPackage.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installedPackage.aspx.cs index 3b5dd9fb2b..8e75bdaae1 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installedPackage.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installedPackage.aspx.cs @@ -335,6 +335,20 @@ namespace umbraco.presentation.developer.packages bt_uninstall.Visible = false; pane_uninstall.Visible = false; } + + // List the package version history [LK 2013-067-10] + Version v; + var packageVersionHistory = cms.businesslogic.packager.InstalledPackage.GetAllInstalledPackages() + .Where(x => x.Data.Id != _pack.Data.Id && string.Equals(x.Data.Name, _pack.Data.Name, StringComparison.OrdinalIgnoreCase)) + .OrderBy(x => Version.TryParse(x.Data.Version, out v) ? v : new Version()); + + if (packageVersionHistory != null && packageVersionHistory.Count() > 0) + { + rptr_versions.DataSource = packageVersionHistory; + rptr_versions.DataBind(); + + pane_versions.Visible = true; + } } } } @@ -611,6 +625,8 @@ namespace umbraco.presentation.developer.packages pp_upgradeInstruction.Text = ui.Text("packager", "packageUpgradeInstructions"); bt_gotoUpgrade.Text = ui.Text("packager", "packageUpgradeDownload"); + pane_versions.Text = ui.Text("packager", "packageVersionHistory"); + pane_noItems.Text = ui.Text("packager", "packageNoItemsHeader"); pane_uninstall.Text = ui.Text("packager", "packageUninstallHeader"); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installedPackage.aspx.designer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installedPackage.aspx.designer.cs index 398a23466d..e6dfc46646 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installedPackage.aspx.designer.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installedPackage.aspx.designer.cs @@ -1,10 +1,9 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.4200 // // Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. +// the code is regenerated. // //------------------------------------------------------------------------------ @@ -175,6 +174,33 @@ namespace umbraco.presentation.developer.packages { /// protected global::System.Web.UI.WebControls.Literal lt_readme; + /// + /// pane_versions control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.Pane pane_versions; + + /// + /// pp_versions control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_versions; + + /// + /// rptr_versions control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Repeater rptr_versions; + /// /// pane_options control. /// diff --git a/src/umbraco.businesslogic/GlobalSettings.cs b/src/umbraco.businesslogic/GlobalSettings.cs index dd77f843b1..1ba730ecfb 100644 --- a/src/umbraco.businesslogic/GlobalSettings.cs +++ b/src/umbraco.businesslogic/GlobalSettings.cs @@ -101,31 +101,6 @@ namespace umbraco get { return Umbraco.Core.SystemUtilities.GetCurrentTrustLevel(); } } - - /// - /// Forces umbraco to be medium trust compatible - /// - /// If true, umbraco will be medium-trust compatible, no matter what Permission level the server is on. - [Obsolete("This property is no longer used and will be removed in future versions")] - public static bool UseMediumTrust - { - get - { - try - { - var trustLevel = SystemUtilities.GetCurrentTrustLevel(); - if (trustLevel == AspNetHostingPermissionLevel.High || trustLevel == AspNetHostingPermissionLevel.Unrestricted) - return false; - else - return bool.Parse(ConfigurationManager.AppSettings["umbracoUseMediumTrust"]); - } - catch - { - return false; - } - } - } - /// /// Saves a setting into the configuration file. /// diff --git a/src/umbraco.sln b/src/umbraco.sln index 00132238c0..00674dae46 100644 --- a/src/umbraco.sln +++ b/src/umbraco.sln @@ -94,9 +94,7 @@ Global {4C4C194C-B5E4-4991-8F87-4373E24CC19F}.Release|Any CPU.ActiveCfg = Release|Any CPU {4C4C194C-B5E4-4991-8F87-4373E24CC19F}.Release|Any CPU.Build.0 = Release|Any CPU {3819A550-DCEC-4153-91B4-8BA9F7F0B9B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3819A550-DCEC-4153-91B4-8BA9F7F0B9B4}.Debug|Any CPU.Build.0 = Debug|Any CPU {3819A550-DCEC-4153-91B4-8BA9F7F0B9B4}.Release|Any CPU.ActiveCfg = Debug|Any CPU - {3819A550-DCEC-4153-91B4-8BA9F7F0B9B4}.Release|Any CPU.Build.0 = Debug|Any CPU {651E1350-91B6-44B7-BD60-7207006D7003}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {651E1350-91B6-44B7-BD60-7207006D7003}.Debug|Any CPU.Build.0 = Debug|Any CPU {651E1350-91B6-44B7-BD60-7207006D7003}.Release|Any CPU.ActiveCfg = Release|Any CPU