├── src ├── VstsDockerBuild.WebApp │ ├── wwwroot │ │ ├── js │ │ │ ├── site.min.js │ │ │ └── site.js │ │ ├── favicon.ico │ │ ├── lib │ │ │ ├── bootstrap │ │ │ │ ├── dist │ │ │ │ │ ├── fonts │ │ │ │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ │ │ │ └── glyphicons-halflings-regular.woff2 │ │ │ │ │ ├── js │ │ │ │ │ │ └── npm.js │ │ │ │ │ └── css │ │ │ │ │ │ ├── bootstrap-theme.min.css.map │ │ │ │ │ │ └── bootstrap-theme.css │ │ │ │ ├── .bower.json │ │ │ │ └── LICENSE │ │ │ ├── jquery │ │ │ │ ├── .bower.json │ │ │ │ └── LICENSE.txt │ │ │ ├── jquery-validation │ │ │ │ ├── .bower.json │ │ │ │ ├── LICENSE.md │ │ │ │ └── dist │ │ │ │ │ └── additional-methods.js │ │ │ └── jquery-validation-unobtrusive │ │ │ │ ├── .bower.json │ │ │ │ ├── jquery.validate.unobtrusive.min.js │ │ │ │ └── jquery.validate.unobtrusive.js │ │ ├── css │ │ │ ├── site.min.css │ │ │ └── site.css │ │ └── images │ │ │ ├── banner2.svg │ │ │ ├── banner1.svg │ │ │ ├── banner3.svg │ │ │ └── banner4.svg │ ├── Pages │ │ ├── _ViewStart.cshtml │ │ ├── _ViewImports.cshtml │ │ ├── About.cshtml │ │ ├── Index.cshtml.cs │ │ ├── About.cshtml.cs │ │ ├── Contact.cshtml │ │ ├── Error.cshtml.cs │ │ ├── Contact.cshtml.cs │ │ ├── Error.cshtml │ │ ├── _ValidationScriptsPartial.cshtml │ │ ├── _Layout.cshtml │ │ └── Index.cshtml │ ├── appsettings.json │ ├── appsettings.Development.json │ ├── Dockerfile │ ├── Controllers │ │ └── StatusController.cs │ ├── VstsDockerBuild.WebApp.csproj │ ├── bundleconfig.json │ ├── Program.cs │ └── Startup.cs ├── VstsDockerBuild.Shared │ ├── VstsDockerBuild.Shared.csproj │ └── Foo.cs └── VstsDockerBuild.PongService │ ├── VstsDockerBuild.PongService.csproj │ ├── Dockerfile │ ├── Program.cs │ └── Startup.cs ├── .gitattributes ├── tests ├── VstsDockerBuild.Tests │ ├── Dockerfile │ ├── UnitTest1.cs │ └── VstsDockerBuild.Tests.csproj └── VstsDockerBuild.IntegrationTests │ ├── Dockerfile │ ├── VstsDockerBuild.IntegrationTests.csproj │ ├── PongServiceIntegrationTests.cs │ └── WebAppIntegrationTests.cs ├── .dockerignore ├── docker-compose.ci.build.yml ├── docker-compose.tests.yml ├── docker-compose.yml ├── docker-compose.integration-tests-vsts.yml ├── docker-compose.override.yml ├── docker-compose.dcproj ├── docker-compose.integration-tests.yml ├── LICENSE ├── README.md ├── VstsDockerBuild.sln └── .gitignore /src/VstsDockerBuild.WebApp/wwwroot/js/site.min.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Write your Javascript code. 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christiansparre/VstsDockerBuild/HEAD/src/VstsDockerBuild.WebApp/wwwroot/favicon.ico -------------------------------------------------------------------------------- /tests/VstsDockerBuild.Tests/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM microsoft/dotnet:2.0-sdk-jessie AS build 2 | 3 | COPY . ./app 4 | WORKDIR /app/tests/VstsDockerBuild.Tests 5 | RUN dotnet restore -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using VstsDockerBuild.WebApp 2 | @namespace VstsDockerBuild.WebApp.Pages 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | -------------------------------------------------------------------------------- /tests/VstsDockerBuild.IntegrationTests/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM microsoft/dotnet:2.0-sdk-jessie AS build 2 | 3 | COPY . ./app 4 | WORKDIR /app/tests/VstsDockerBuild.IntegrationTests 5 | RUN dotnet restore -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .dockerignore 2 | .env 3 | .git 4 | .gitignore 5 | .vs 6 | .vscode 7 | docker-compose.yml 8 | docker-compose.*.yml 9 | */bin 10 | */obj 11 | !obj/Docker/publish/* 12 | !obj/Docker/empty/ 13 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.Shared/VstsDockerBuild.Shared.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.Shared/Foo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace VstsDockerBuild.Shared 4 | { 5 | public class Foo 6 | { 7 | public string Bar() => DateTime.UtcNow.ToLongDateString(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Warning" 6 | } 7 | }, 8 | "PongService": "http://localhost:59015/" 9 | } 10 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christiansparre/VstsDockerBuild/HEAD/src/VstsDockerBuild.WebApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christiansparre/VstsDockerBuild/HEAD/src/VstsDockerBuild.WebApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christiansparre/VstsDockerBuild/HEAD/src/VstsDockerBuild.WebApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christiansparre/VstsDockerBuild/HEAD/src/VstsDockerBuild.WebApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/Pages/About.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model AboutModel 3 | @{ 4 | ViewData["Title"] = "About"; 5 | } 6 |

@ViewData["Title"]

7 |

@Model.Message

8 | 9 |

Use this area to provide additional information.

10 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Debug", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/css/site.min.css: -------------------------------------------------------------------------------- 1 | body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}.carousel-caption p{font-size:20px;line-height:1.4}.carousel-inner .item img[src$=".svg"]{width:100%}#qrCode{margin:15px}@media screen and (max-width:767px){.carousel-caption{display:none}} -------------------------------------------------------------------------------- /docker-compose.ci.build.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | ci-build: 5 | image: microsoft/aspnetcore-build:1.0-2.0 6 | volumes: 7 | - .:/src 8 | working_dir: /src 9 | command: /bin/bash -c "dotnet restore ./VstsDockerBuild.sln && dotnet publish ./VstsDockerBuild.sln -c Release -o ./obj/Docker/publish" 10 | -------------------------------------------------------------------------------- /docker-compose.tests.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | vstsdockerbuild.tests: 5 | environment: 6 | - BLOWUP 7 | image: vstsdockerbuild.tests 8 | build: 9 | context: . 10 | dockerfile: tests/VstsDockerBuild.Tests/Dockerfile 11 | entrypoint: dotnet test --logger trx --results-directory /var/temp 12 | volumes: 13 | - /opt/vsts/work/_temp:/var/temp -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | vstsdockerbuild.webapp: 5 | image: vstsdockerbuild.webapp 6 | build: 7 | context: . 8 | dockerfile: src/VstsDockerBuild.WebApp/Dockerfile 9 | 10 | vstsdockerbuild.pongservice: 11 | image: vstsdockerbuild.pongservice 12 | build: 13 | context: . 14 | dockerfile: src/VstsDockerBuild.PongService/Dockerfile 15 | 16 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/Pages/Index.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | 8 | namespace VstsDockerBuild.WebApp.Pages 9 | { 10 | public class IndexModel : PageModel 11 | { 12 | public void OnGet() 13 | { 14 | 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /docker-compose.integration-tests-vsts.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | vstsdockerbuild.webapp: 5 | image: sparreio.azurecr.io/vstsdockerbuild.webapp 6 | 7 | vstsdockerbuild.pongservice: 8 | image: sparreio.azurecr.io/vstsdockerbuild.pongservice 9 | 10 | vstsdockerbuild.integrationtests: 11 | entrypoint: dotnet test --logger trx --results-directory /var/temp 12 | volumes: 13 | - /opt/vsts/work/_temp:/var/temp 14 | -------------------------------------------------------------------------------- /docker-compose.override.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | vstsdockerbuild.webapp: 5 | environment: 6 | - ASPNETCORE_ENVIRONMENT=Development 7 | - PongService=http://vstsdockerbuild.pongservice 8 | ports: 9 | - "8080:80" 10 | depends_on: 11 | - vstsdockerbuild.pongservice 12 | 13 | vstsdockerbuild.pongservice: 14 | environment: 15 | - ASPNETCORE_ENVIRONMENT=Development 16 | ports: 17 | - "80" 18 | 19 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/Pages/About.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc.RazorPages; 6 | 7 | namespace VstsDockerBuild.WebApp.Pages 8 | { 9 | public class AboutModel : PageModel 10 | { 11 | public string Message { get; set; } 12 | 13 | public void OnGet() 14 | { 15 | Message = "Your application description page."; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.PongService/VstsDockerBuild.PongService.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | ..\..\docker-compose.dcproj 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/bootstrap/dist/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/Pages/Contact.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ContactModel 3 | @{ 4 | ViewData["Title"] = "Contact"; 5 | } 6 |

@ViewData["Title"]

7 |

@Model.Message

8 | 9 |
10 | One Microsoft Way
11 | Redmond, WA 98052-6399
12 | P: 13 | 425.555.0100 14 |
15 | 16 |
17 | Support: Support@example.com
18 | Marketing: Marketing@example.com 19 |
20 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM microsoft/aspnetcore:2.0 AS base 2 | WORKDIR /app 3 | EXPOSE 80 4 | 5 | FROM microsoft/aspnetcore-build:2.0 AS build 6 | WORKDIR /src 7 | COPY *.sln ./ 8 | COPY src/VstsDockerBuild.WebApp/VstsDockerBuild.WebApp.csproj src/VstsDockerBuild.WebApp/ 9 | RUN dotnet restore 10 | COPY . . 11 | WORKDIR /src/src/VstsDockerBuild.WebApp 12 | RUN dotnet build -c Release -o /app 13 | 14 | FROM build AS publish 15 | RUN dotnet publish -c Release -o /app 16 | 17 | FROM base AS final 18 | WORKDIR /app 19 | COPY --from=publish /app . 20 | ENTRYPOINT ["dotnet", "VstsDockerBuild.WebApp.dll"] 21 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/Controllers/StatusController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace VstsDockerBuild.WebApp.Controllers 5 | { 6 | public class StatusController:Controller 7 | { 8 | [HttpGet("status")] 9 | public IActionResult Status() 10 | { 11 | var blowUp = Environment.GetEnvironmentVariable("BLOWUP"); 12 | if (blowUp != null && blowUp == "yes") 13 | { 14 | return StatusCode(500); 15 | } 16 | 17 | return Ok("All is right in the world"); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/Pages/Error.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | 8 | namespace VstsDockerBuild.WebApp.Pages 9 | { 10 | public class ErrorModel : PageModel 11 | { 12 | public string RequestId { get; set; } 13 | 14 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 15 | 16 | public void OnGet() 17 | { 18 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/VstsDockerBuild.IntegrationTests/VstsDockerBuild.IntegrationTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.PongService/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM microsoft/aspnetcore:2.0 AS base 2 | WORKDIR /app 3 | EXPOSE 80 4 | 5 | FROM microsoft/aspnetcore-build:2.0 AS build 6 | WORKDIR /src 7 | COPY *.sln ./ 8 | COPY src/VstsDockerBuild.PongService/VstsDockerBuild.PongService.csproj src/VstsDockerBuild.PongService/ 9 | RUN dotnet restore 10 | COPY . . 11 | WORKDIR /src/src/VstsDockerBuild.PongService 12 | RUN dotnet build -c Release -o /app 13 | 14 | FROM build AS publish 15 | RUN dotnet publish -c Release -o /app 16 | 17 | FROM base AS final 18 | WORKDIR /app 19 | COPY --from=publish /app . 20 | ENTRYPOINT ["dotnet", "VstsDockerBuild.PongService.dll"] 21 | -------------------------------------------------------------------------------- /tests/VstsDockerBuild.IntegrationTests/PongServiceIntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using Xunit; 5 | 6 | namespace VstsDockerBuild.IntegrationTests 7 | { 8 | public class PongServiceIntegrationTests 9 | { 10 | [Fact] 11 | public async Task ItWorks() 12 | { 13 | var client = new HttpClient(); 14 | 15 | var pongServiceUrl = Environment.GetEnvironmentVariable("PongService"); 16 | 17 | var s = await client.GetStringAsync(pongServiceUrl); 18 | 19 | Assert.Equal("Pong!", s); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/jquery/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "main": "dist/jquery.js", 4 | "license": "MIT", 5 | "ignore": [ 6 | "package.json" 7 | ], 8 | "keywords": [ 9 | "jquery", 10 | "javascript", 11 | "browser", 12 | "library" 13 | ], 14 | "homepage": "https://github.com/jquery/jquery-dist", 15 | "version": "2.2.0", 16 | "_release": "2.2.0", 17 | "_resolution": { 18 | "type": "version", 19 | "tag": "2.2.0", 20 | "commit": "6fc01e29bdad0964f62ef56d01297039cdcadbe5" 21 | }, 22 | "_source": "git://github.com/jquery/jquery-dist.git", 23 | "_target": "2.2.0", 24 | "_originalSource": "jquery" 25 | } -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/VstsDockerBuild.WebApp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netcoreapp2.0 4 | ..\..\docker-compose.dcproj 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/bundleconfig.json: -------------------------------------------------------------------------------- 1 | // Configure bundling and minification for the project. 2 | // More info at https://go.microsoft.com/fwlink/?LinkId=808241 3 | [ 4 | { 5 | "outputFileName": "wwwroot/css/site.min.css", 6 | // An array of relative input file paths. Globbing patterns supported 7 | "inputFiles": [ 8 | "wwwroot/css/site.css" 9 | ] 10 | }, 11 | { 12 | "outputFileName": "wwwroot/js/site.min.js", 13 | "inputFiles": [ 14 | "wwwroot/js/site.js" 15 | ], 16 | // Optionally specify minification options 17 | "minify": { 18 | "enabled": true, 19 | "renameLocals": true 20 | }, 21 | // Optionally generate .map file 22 | "sourceMap": false 23 | } 24 | ] 25 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace VstsDockerBuild.WebApp 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | BuildWebHost(args).Run(); 18 | } 19 | 20 | public static IWebHost BuildWebHost(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup() 23 | .Build(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.PongService/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace VstsDockerBuild.PongService 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | BuildWebHost(args).Run(); 18 | } 19 | 20 | public static IWebHost BuildWebHost(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup() 23 | .Build(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/VstsDockerBuild.IntegrationTests/WebAppIntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Net.Http; 4 | using System.Threading.Tasks; 5 | using Xunit; 6 | 7 | namespace VstsDockerBuild.IntegrationTests 8 | { 9 | public class WebAppIntegrationTests 10 | { 11 | [Fact] 12 | public async Task ItWorks() 13 | { 14 | var client = new HttpClient(); 15 | 16 | var webAppUrl = Environment.GetEnvironmentVariable("WebApp"); 17 | 18 | var r = await client.GetAsync($"{webAppUrl}/status"); 19 | 20 | Assert.Equal(HttpStatusCode.OK, r.StatusCode); 21 | 22 | var s = await r.Content.ReadAsStringAsync(); 23 | 24 | Assert.Equal("All is right in the world", s); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/VstsDockerBuild.PongService/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.Http; 4 | using Microsoft.Extensions.DependencyInjection; 5 | 6 | namespace VstsDockerBuild.PongService 7 | { 8 | public class Startup 9 | { 10 | public void ConfigureServices(IServiceCollection services) 11 | { 12 | 13 | } 14 | 15 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 16 | { 17 | if (env.IsDevelopment()) 18 | { 19 | app.UseDeveloperExceptionPage(); 20 | } 21 | 22 | app.Run(async (context) => 23 | { 24 | await context.Response.WriteAsync("Pong!"); 25 | }); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/VstsDockerBuild.Tests/UnitTest1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace VstsDockerBuild.Tests 5 | { 6 | public class UnitTest1 7 | { 8 | [Fact] 9 | public void Test1() 10 | { 11 | var blowUp = Environment.GetEnvironmentVariable("BLOWUP"); 12 | 13 | if (blowUp != null) 14 | { 15 | Assert.NotEqual("yes", blowUp); 16 | } 17 | 18 | } 19 | 20 | [Fact] 21 | public void Test2() 22 | { 23 | 24 | } 25 | 26 | [Fact] 27 | public void Test3() 28 | { 29 | 30 | } 31 | 32 | [Fact] 33 | public void Test4() 34 | { 35 | 36 | } 37 | 38 | [Fact] 39 | public void Test5() 40 | { 41 | 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 50px; 3 | padding-bottom: 20px; 4 | } 5 | 6 | /* Wrapping element */ 7 | /* Set some basic padding to keep content from hitting the edges */ 8 | .body-content { 9 | padding-left: 15px; 10 | padding-right: 15px; 11 | } 12 | 13 | /* Carousel */ 14 | .carousel-caption p { 15 | font-size: 20px; 16 | line-height: 1.4; 17 | } 18 | 19 | /* Make .svg files in the carousel display properly in older browsers */ 20 | .carousel-inner .item img[src$=".svg"] { 21 | width: 100%; 22 | } 23 | 24 | /* QR code generator */ 25 | #qrCode { 26 | margin: 15px; 27 | } 28 | 29 | /* Hide/rearrange for smaller screens */ 30 | @media screen and (max-width: 767px) { 31 | /* Hide captions */ 32 | .carousel-caption { 33 | display: none; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /docker-compose.dcproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2.0 5 | Linux 6 | e579b631-6509-42ea-bd4d-d4e127ad814a 7 | True 8 | http://localhost:{ServicePort} 9 | vstsdockerbuild.webapp 10 | 11 | 12 | 13 | docker-compose.yml 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/VstsDockerBuild.Tests/VstsDockerBuild.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/Pages/Contact.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | using Microsoft.Extensions.Configuration; 8 | 9 | namespace VstsDockerBuild.WebApp.Pages 10 | { 11 | public class ContactModel : PageModel 12 | { 13 | private readonly IConfiguration _configuration; 14 | private readonly HttpClient _client; 15 | 16 | public ContactModel(IConfiguration configuration, HttpClient client) 17 | { 18 | _configuration = configuration; 19 | _client = client; 20 | } 21 | 22 | public string Message { get; set; } 23 | 24 | public async Task OnGet() 25 | { 26 | var r = await _client.GetStringAsync(_configuration["PongService"]); 27 | 28 | Message = $"My Ping! Your {r}"; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/Pages/Error.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ErrorModel 3 | @{ 4 | ViewData["Title"] = "Error"; 5 | } 6 | 7 |

Error.

8 |

An error occurred while processing your request.

9 | 10 | @if (Model.ShowRequestId) 11 | { 12 |

13 | Request ID: @Model.RequestId 14 |

15 | } 16 | 17 |

Development Mode

18 |

19 | Swapping to Development environment will display more detailed information about the error that occurred. 20 |

21 |

22 | Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. 23 |

24 | -------------------------------------------------------------------------------- /docker-compose.integration-tests.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | vstsdockerbuild.webapp: 5 | image: vstsdockerbuild.webapp 6 | environment: 7 | - ASPNETCORE_ENVIRONMENT=Development 8 | - PongService=http://vstsdockerbuild.pongservice 9 | - BLOWUP 10 | ports: 11 | - "80" 12 | depends_on: 13 | - vstsdockerbuild.pongservice 14 | logging: 15 | driver: "none" 16 | 17 | vstsdockerbuild.pongservice: 18 | image: vstsdockerbuild.pongservice 19 | environment: 20 | - ASPNETCORE_ENVIRONMENT=Development 21 | ports: 22 | - "80" 23 | logging: 24 | driver: "none" 25 | 26 | vstsdockerbuild.integrationtests: 27 | image: vstsdockerbuild.integrationtests 28 | build: 29 | context: . 30 | dockerfile: tests/VstsDockerBuild.IntegrationTests/Dockerfile 31 | entrypoint: dotnet test 32 | environment: 33 | - PongService=http://vstsdockerbuild.pongservice 34 | - WebApp=http://vstsdockerbuild.webapp 35 | depends_on: 36 | - vstsdockerbuild.pongservice 37 | - vstsdockerbuild.webapp 38 | 39 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/jquery-validation/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation", 3 | "homepage": "http://jqueryvalidation.org/", 4 | "repository": { 5 | "type": "git", 6 | "url": "git://github.com/jzaefferer/jquery-validation.git" 7 | }, 8 | "authors": [ 9 | "Jörn Zaefferer " 10 | ], 11 | "description": "Form validation made easy", 12 | "main": "dist/jquery.validate.js", 13 | "keywords": [ 14 | "forms", 15 | "validation", 16 | "validate" 17 | ], 18 | "license": "MIT", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "demo", 25 | "lib" 26 | ], 27 | "dependencies": { 28 | "jquery": ">= 1.7.2" 29 | }, 30 | "version": "1.14.0", 31 | "_release": "1.14.0", 32 | "_resolution": { 33 | "type": "version", 34 | "tag": "1.14.0", 35 | "commit": "c1343fb9823392aa9acbe1c3ffd337b8c92fed48" 36 | }, 37 | "_source": "git://github.com/jzaefferer/jquery-validation.git", 38 | "_target": ">=1.8", 39 | "_originalSource": "jquery-validation" 40 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 sparreio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/bootstrap/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap", 3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", 4 | "keywords": [ 5 | "css", 6 | "js", 7 | "less", 8 | "mobile-first", 9 | "responsive", 10 | "front-end", 11 | "framework", 12 | "web" 13 | ], 14 | "homepage": "http://getbootstrap.com", 15 | "license": "MIT", 16 | "moduleType": "globals", 17 | "main": [ 18 | "less/bootstrap.less", 19 | "dist/js/bootstrap.js" 20 | ], 21 | "ignore": [ 22 | "/.*", 23 | "_config.yml", 24 | "CNAME", 25 | "composer.json", 26 | "CONTRIBUTING.md", 27 | "docs", 28 | "js/tests", 29 | "test-infra" 30 | ], 31 | "dependencies": { 32 | "jquery": "1.9.1 - 3" 33 | }, 34 | "version": "3.3.7", 35 | "_release": "3.3.7", 36 | "_resolution": { 37 | "type": "version", 38 | "tag": "v3.3.7", 39 | "commit": "0b9c4a4007c44201dce9a6cc1a38407005c26c86" 40 | }, 41 | "_source": "https://github.com/twbs/bootstrap.git", 42 | "_target": "v3.3.7", 43 | "_originalSource": "bootstrap", 44 | "_direct": true 45 | } -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2016 Twitter, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/Startup.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.Extensions.Configuration; 5 | using Microsoft.Extensions.DependencyInjection; 6 | 7 | namespace VstsDockerBuild.WebApp 8 | { 9 | public class Startup 10 | { 11 | public Startup(IConfiguration configuration) 12 | { 13 | Configuration = configuration; 14 | } 15 | 16 | public IConfiguration Configuration { get; } 17 | 18 | public void ConfigureServices(IServiceCollection services) 19 | { 20 | services.AddSingleton(s => new HttpClient()); 21 | 22 | services.AddMvc(); 23 | } 24 | 25 | 26 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 27 | { 28 | if (env.IsDevelopment()) 29 | { 30 | app.UseBrowserLink(); 31 | app.UseDeveloperExceptionPage(); 32 | } 33 | else 34 | { 35 | app.UseExceptionHandler("/Error"); 36 | } 37 | 38 | app.UseStaticFiles(); 39 | 40 | app.UseMvc(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/Pages/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/jquery-validation-unobtrusive/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation-unobtrusive", 3 | "version": "3.2.6", 4 | "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive", 5 | "description": "Add-on to jQuery Validation to enable unobtrusive validation options in data-* attributes.", 6 | "main": [ 7 | "jquery.validate.unobtrusive.js" 8 | ], 9 | "ignore": [ 10 | "**/.*", 11 | "*.json", 12 | "*.md", 13 | "*.txt", 14 | "gulpfile.js" 15 | ], 16 | "keywords": [ 17 | "jquery", 18 | "asp.net", 19 | "mvc", 20 | "validation", 21 | "unobtrusive" 22 | ], 23 | "authors": [ 24 | "Microsoft" 25 | ], 26 | "license": "http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm", 27 | "repository": { 28 | "type": "git", 29 | "url": "git://github.com/aspnet/jquery-validation-unobtrusive.git" 30 | }, 31 | "dependencies": { 32 | "jquery-validation": ">=1.8", 33 | "jquery": ">=1.8" 34 | }, 35 | "_release": "3.2.6", 36 | "_resolution": { 37 | "type": "version", 38 | "tag": "v3.2.6", 39 | "commit": "13386cd1b5947d8a5d23a12b531ce3960be1eba7" 40 | }, 41 | "_source": "git://github.com/aspnet/jquery-validation-unobtrusive.git", 42 | "_target": "3.2.6", 43 | "_originalSource": "jquery-validation-unobtrusive" 44 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Building Docker images using Visual Studio Team Services 2 | _and running unit- and integrationtests using docker-compose_ 3 | 4 | ## The solution 5 | The solution consist of multiple projects 6 | * A WebApp project 7 | * A Shared library project 8 | * A "Service" project 9 | * A project with a few empty unit tests 10 | * And a project with a few integration test 11 | 12 | ## The repository contains 13 | I wanted to explore how to setup a complete build pipeline in VSTS for building multi image solutions. The examples I have been able to find were all very simple, as "getting" started guides tend to be. This is ok, but I wanted to take it just a little bit further. 14 | 15 | So here I have set up a more complete sample solution that 16 | 17 | 1. Builds multiple projects into docker images. 18 | 1. Runs a number of empty unit tests 19 | 1. Runs a few integration tests 20 | 21 | These blog posts talks about the different parts of the sample 22 | 23 | Post 1: https://medium.com/@christiansparre/building-a-multi-docker-image-solution-using-visual-studio-team-services-and-docker-compose-42fa196b6cd2 24 | 25 | Post 2: https://medium.com/@christiansparre/running-your-unit-tests-with-visual-studio-team-services-and-docker-compose-3f82c9b95bf 26 | 27 | I think the most interesting thing and one of the huge value propositions for docker, besides the general awesomeness, is how easy it actually is to setup integration tests of a complete solution. It does not involve deployment, it can easily run as part of your build pipeline and it can include everything from your own application to database servers etc. 28 | 29 | Take a look 30 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright jQuery Foundation and other contributors, https://jquery.org/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | All files located in the node_modules and external directories are 34 | externally maintained libraries used by this software which have their 35 | own licenses; we recommend you read them, as their terms may differ from 36 | the terms above. 37 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/Pages/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | @using Shared 2 | @{ 3 | var bar = new Foo().Bar(); 4 | } 5 | 6 | 7 | 8 | 9 | 10 | @ViewData["Title"] - VstsDockerBuild.WebApp 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 | 21 | 22 | 23 | 24 | 44 |
45 |
@bar
46 | @RenderBody() 47 |
48 |
49 |

© 2017 - VstsDockerBuild.WebApp

50 |
51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 71 | 72 | 73 | 74 | @RenderSection("Scripts", required: false) 75 | 76 | 77 | -------------------------------------------------------------------------------- /VstsDockerBuild.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2036 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{265CE66D-F273-4516-8762-E8C9D732C11A}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VstsDockerBuild.WebApp", "src\VstsDockerBuild.WebApp\VstsDockerBuild.WebApp.csproj", "{29E03BCE-D9D9-4533-A31E-3867E70553D1}" 9 | EndProject 10 | Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{E579B631-6509-42EA-BD4D-D4E127AD814A}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VstsDockerBuild.Shared", "src\VstsDockerBuild.Shared\VstsDockerBuild.Shared.csproj", "{49ED9822-D0BA-43CD-A1AE-817BB4576743}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VstsDockerBuild.PongService", "src\VstsDockerBuild.PongService\VstsDockerBuild.PongService.csproj", "{8D99827A-9651-4C10-BF90-DBCFFF276E8E}" 15 | EndProject 16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{779787A8-B13A-49D6-84CF-9277ED0D868A}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VstsDockerBuild.Tests", "tests\VstsDockerBuild.Tests\VstsDockerBuild.Tests.csproj", "{1E05649D-E100-4202-B0E8-321D4907CCD6}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VstsDockerBuild.IntegrationTests", "tests\VstsDockerBuild.IntegrationTests\VstsDockerBuild.IntegrationTests.csproj", "{3B2103FC-1FD0-4B68-AB62-23E11798C158}" 21 | EndProject 22 | Global 23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 24 | Debug|Any CPU = Debug|Any CPU 25 | Release|Any CPU = Release|Any CPU 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {29E03BCE-D9D9-4533-A31E-3867E70553D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {29E03BCE-D9D9-4533-A31E-3867E70553D1}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {29E03BCE-D9D9-4533-A31E-3867E70553D1}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {29E03BCE-D9D9-4533-A31E-3867E70553D1}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {E579B631-6509-42EA-BD4D-D4E127AD814A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {E579B631-6509-42EA-BD4D-D4E127AD814A}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {E579B631-6509-42EA-BD4D-D4E127AD814A}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {E579B631-6509-42EA-BD4D-D4E127AD814A}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {49ED9822-D0BA-43CD-A1AE-817BB4576743}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {49ED9822-D0BA-43CD-A1AE-817BB4576743}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {49ED9822-D0BA-43CD-A1AE-817BB4576743}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {49ED9822-D0BA-43CD-A1AE-817BB4576743}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {8D99827A-9651-4C10-BF90-DBCFFF276E8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {8D99827A-9651-4C10-BF90-DBCFFF276E8E}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {8D99827A-9651-4C10-BF90-DBCFFF276E8E}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {8D99827A-9651-4C10-BF90-DBCFFF276E8E}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {1E05649D-E100-4202-B0E8-321D4907CCD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {1E05649D-E100-4202-B0E8-321D4907CCD6}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {1E05649D-E100-4202-B0E8-321D4907CCD6}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {1E05649D-E100-4202-B0E8-321D4907CCD6}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {3B2103FC-1FD0-4B68-AB62-23E11798C158}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {3B2103FC-1FD0-4B68-AB62-23E11798C158}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {3B2103FC-1FD0-4B68-AB62-23E11798C158}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {3B2103FC-1FD0-4B68-AB62-23E11798C158}.Release|Any CPU.Build.0 = Release|Any CPU 52 | EndGlobalSection 53 | GlobalSection(SolutionProperties) = preSolution 54 | HideSolutionNode = FALSE 55 | EndGlobalSection 56 | GlobalSection(NestedProjects) = preSolution 57 | {29E03BCE-D9D9-4533-A31E-3867E70553D1} = {265CE66D-F273-4516-8762-E8C9D732C11A} 58 | {49ED9822-D0BA-43CD-A1AE-817BB4576743} = {265CE66D-F273-4516-8762-E8C9D732C11A} 59 | {8D99827A-9651-4C10-BF90-DBCFFF276E8E} = {265CE66D-F273-4516-8762-E8C9D732C11A} 60 | {1E05649D-E100-4202-B0E8-321D4907CCD6} = {779787A8-B13A-49D6-84CF-9277ED0D868A} 61 | {3B2103FC-1FD0-4B68-AB62-23E11798C158} = {779787A8-B13A-49D6-84CF-9277ED0D868A} 62 | EndGlobalSection 63 | GlobalSection(ExtensibilityGlobals) = postSolution 64 | SolutionGuid = {28B5493E-8D7F-4A95-9B39-7D245F378B01} 65 | EndGlobalSection 66 | EndGlobal 67 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | ** Unobtrusive validation support library for jQuery and jQuery Validate 3 | ** Copyright (C) Microsoft Corporation. All rights reserved. 4 | */ 5 | !function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a("
  • ").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function m(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=p.unobtrusive.options||{},m=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),m("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),m("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),m("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var u,p=a.validator,v="unobtrusiveValidation";p.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=m(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){p.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=m(this);a&&a.attachValidation()})}},u=p.unobtrusive.adapters,u.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},u.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},u.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},u.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},p.addMethod("__dummy__",function(a,e,n){return!0}),p.addMethod("regex",function(a,e,n){var t;return this.optional(e)?!0:(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),p.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),p.methods.extension?(u.addSingleVal("accept","mimtype"),u.addSingleVal("extension","extension")):u.addSingleVal("extension","extension","accept"),u.addSingleVal("regex","pattern"),u.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),u.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),u.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),u.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),u.add("required",function(a){("INPUT"!==a.element.tagName.toUpperCase()||"CHECKBOX"!==a.element.type.toUpperCase())&&e(a,"required",!0)}),u.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),u.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),a(function(){p.unobtrusive.parse(document)})}(jQuery); -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/Pages/Index.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model IndexModel 3 | @{ 4 | ViewData["Title"] = "Home page"; 5 | } 6 | 7 | 69 | 70 | 109 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # Benchmark Results 46 | BenchmarkDotNet.Artifacts/ 47 | 48 | # .NET Core 49 | project.lock.json 50 | project.fragment.lock.json 51 | artifacts/ 52 | **/Properties/launchSettings.json 53 | 54 | *_i.c 55 | *_p.c 56 | *_i.h 57 | *.ilk 58 | *.meta 59 | *.obj 60 | *.pch 61 | *.pdb 62 | *.pgc 63 | *.pgd 64 | *.rsp 65 | *.sbr 66 | *.tlb 67 | *.tli 68 | *.tlh 69 | *.tmp 70 | *.tmp_proj 71 | *.log 72 | *.vspscc 73 | *.vssscc 74 | .builds 75 | *.pidb 76 | *.svclog 77 | *.scc 78 | 79 | # Chutzpah Test files 80 | _Chutzpah* 81 | 82 | # Visual C++ cache files 83 | ipch/ 84 | *.aps 85 | *.ncb 86 | *.opendb 87 | *.opensdf 88 | *.sdf 89 | *.cachefile 90 | *.VC.db 91 | *.VC.VC.opendb 92 | 93 | # Visual Studio profiler 94 | *.psess 95 | *.vsp 96 | *.vspx 97 | *.sap 98 | 99 | # TFS 2012 Local Workspace 100 | $tf/ 101 | 102 | # Guidance Automation Toolkit 103 | *.gpState 104 | 105 | # ReSharper is a .NET coding add-in 106 | _ReSharper*/ 107 | *.[Rr]e[Ss]harper 108 | *.DotSettings.user 109 | 110 | # JustCode is a .NET coding add-in 111 | .JustCode 112 | 113 | # TeamCity is a build add-in 114 | _TeamCity* 115 | 116 | # DotCover is a Code Coverage Tool 117 | *.dotCover 118 | 119 | # AxoCover is a Code Coverage Tool 120 | .axoCover/* 121 | !.axoCover/settings.json 122 | 123 | # Visual Studio code coverage results 124 | *.coverage 125 | *.coveragexml 126 | 127 | # NCrunch 128 | _NCrunch_* 129 | .*crunch*.local.xml 130 | nCrunchTemp_* 131 | 132 | # MightyMoose 133 | *.mm.* 134 | AutoTest.Net/ 135 | 136 | # Web workbench (sass) 137 | .sass-cache/ 138 | 139 | # Installshield output folder 140 | [Ee]xpress/ 141 | 142 | # DocProject is a documentation generator add-in 143 | DocProject/buildhelp/ 144 | DocProject/Help/*.HxT 145 | DocProject/Help/*.HxC 146 | DocProject/Help/*.hhc 147 | DocProject/Help/*.hhk 148 | DocProject/Help/*.hhp 149 | DocProject/Help/Html2 150 | DocProject/Help/html 151 | 152 | # Click-Once directory 153 | publish/ 154 | 155 | # Publish Web Output 156 | *.[Pp]ublish.xml 157 | *.azurePubxml 158 | # Note: Comment the next line if you want to checkin your web deploy settings, 159 | # but database connection strings (with potential passwords) will be unencrypted 160 | *.pubxml 161 | *.publishproj 162 | 163 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 164 | # checkin your Azure Web App publish settings, but sensitive information contained 165 | # in these scripts will be unencrypted 166 | PublishScripts/ 167 | 168 | # NuGet Packages 169 | *.nupkg 170 | # The packages folder can be ignored because of Package Restore 171 | **/packages/* 172 | # except build/, which is used as an MSBuild target. 173 | !**/packages/build/ 174 | # Uncomment if necessary however generally it will be regenerated when needed 175 | #!**/packages/repositories.config 176 | # NuGet v3's project.json files produces more ignorable files 177 | *.nuget.props 178 | *.nuget.targets 179 | 180 | # Microsoft Azure Build Output 181 | csx/ 182 | *.build.csdef 183 | 184 | # Microsoft Azure Emulator 185 | ecf/ 186 | rcf/ 187 | 188 | # Windows Store app package directories and files 189 | AppPackages/ 190 | BundleArtifacts/ 191 | Package.StoreAssociation.xml 192 | _pkginfo.txt 193 | *.appx 194 | 195 | # Visual Studio cache files 196 | # files ending in .cache can be ignored 197 | *.[Cc]ache 198 | # but keep track of directories ending in .cache 199 | !*.[Cc]ache/ 200 | 201 | # Others 202 | ClientBin/ 203 | ~$* 204 | *~ 205 | *.dbmdl 206 | *.dbproj.schemaview 207 | *.jfm 208 | *.pfx 209 | *.publishsettings 210 | orleans.codegen.cs 211 | 212 | # Since there are multiple workflows, uncomment next line to ignore bower_components 213 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 214 | #bower_components/ 215 | 216 | # RIA/Silverlight projects 217 | Generated_Code/ 218 | 219 | # Backup & report files from converting an old project file 220 | # to a newer Visual Studio version. Backup files are not needed, 221 | # because we have git ;-) 222 | _UpgradeReport_Files/ 223 | Backup*/ 224 | UpgradeLog*.XML 225 | UpgradeLog*.htm 226 | 227 | # SQL Server files 228 | *.mdf 229 | *.ldf 230 | *.ndf 231 | 232 | # Business Intelligence projects 233 | *.rdl.data 234 | *.bim.layout 235 | *.bim_*.settings 236 | 237 | # Microsoft Fakes 238 | FakesAssemblies/ 239 | 240 | # GhostDoc plugin setting file 241 | *.GhostDoc.xml 242 | 243 | # Node.js Tools for Visual Studio 244 | .ntvs_analysis.dat 245 | node_modules/ 246 | 247 | # Typescript v1 declaration files 248 | typings/ 249 | 250 | # Visual Studio 6 build log 251 | *.plg 252 | 253 | # Visual Studio 6 workspace options file 254 | *.opt 255 | 256 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 257 | *.vbw 258 | 259 | # Visual Studio LightSwitch build output 260 | **/*.HTMLClient/GeneratedArtifacts 261 | **/*.DesktopClient/GeneratedArtifacts 262 | **/*.DesktopClient/ModelManifest.xml 263 | **/*.Server/GeneratedArtifacts 264 | **/*.Server/ModelManifest.xml 265 | _Pvt_Extensions 266 | 267 | # Paket dependency manager 268 | .paket/paket.exe 269 | paket-files/ 270 | 271 | # FAKE - F# Make 272 | .fake/ 273 | 274 | # JetBrains Rider 275 | .idea/ 276 | *.sln.iml 277 | 278 | # CodeRush 279 | .cr/ 280 | 281 | # Python Tools for Visual Studio (PTVS) 282 | __pycache__/ 283 | *.pyc 284 | 285 | # Cake - Uncomment if you are using it 286 | # tools/** 287 | # !tools/packages.config 288 | 289 | # Tabs Studio 290 | *.tss 291 | 292 | # Telerik's JustMock configuration file 293 | *.jmconfig 294 | 295 | # BizTalk build output 296 | *.btp.cs 297 | *.btm.cs 298 | *.odx.cs 299 | *.xsd.cs 300 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/images/banner2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/images/banner1.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/images/banner3.svg: -------------------------------------------------------------------------------- 1 | banner3b -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/images/banner4.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js: -------------------------------------------------------------------------------- 1 | /*! 2 | ** Unobtrusive validation support library for jQuery and jQuery Validate 3 | ** Copyright (C) Microsoft Corporation. All rights reserved. 4 | */ 5 | 6 | /*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */ 7 | /*global document: false, jQuery: false */ 8 | 9 | (function ($) { 10 | var $jQval = $.validator, 11 | adapters, 12 | data_validation = "unobtrusiveValidation"; 13 | 14 | function setValidationValues(options, ruleName, value) { 15 | options.rules[ruleName] = value; 16 | if (options.message) { 17 | options.messages[ruleName] = options.message; 18 | } 19 | } 20 | 21 | function splitAndTrim(value) { 22 | return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g); 23 | } 24 | 25 | function escapeAttributeValue(value) { 26 | // As mentioned on http://api.jquery.com/category/selectors/ 27 | return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1"); 28 | } 29 | 30 | function getModelPrefix(fieldName) { 31 | return fieldName.substr(0, fieldName.lastIndexOf(".") + 1); 32 | } 33 | 34 | function appendModelPrefix(value, prefix) { 35 | if (value.indexOf("*.") === 0) { 36 | value = value.replace("*.", prefix); 37 | } 38 | return value; 39 | } 40 | 41 | function onError(error, inputElement) { // 'this' is the form element 42 | var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"), 43 | replaceAttrValue = container.attr("data-valmsg-replace"), 44 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null; 45 | 46 | container.removeClass("field-validation-valid").addClass("field-validation-error"); 47 | error.data("unobtrusiveContainer", container); 48 | 49 | if (replace) { 50 | container.empty(); 51 | error.removeClass("input-validation-error").appendTo(container); 52 | } 53 | else { 54 | error.hide(); 55 | } 56 | } 57 | 58 | function onErrors(event, validator) { // 'this' is the form element 59 | var container = $(this).find("[data-valmsg-summary=true]"), 60 | list = container.find("ul"); 61 | 62 | if (list && list.length && validator.errorList.length) { 63 | list.empty(); 64 | container.addClass("validation-summary-errors").removeClass("validation-summary-valid"); 65 | 66 | $.each(validator.errorList, function () { 67 | $("
  • ").html(this.message).appendTo(list); 68 | }); 69 | } 70 | } 71 | 72 | function onSuccess(error) { // 'this' is the form element 73 | var container = error.data("unobtrusiveContainer"); 74 | 75 | if (container) { 76 | var replaceAttrValue = container.attr("data-valmsg-replace"), 77 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null; 78 | 79 | container.addClass("field-validation-valid").removeClass("field-validation-error"); 80 | error.removeData("unobtrusiveContainer"); 81 | 82 | if (replace) { 83 | container.empty(); 84 | } 85 | } 86 | } 87 | 88 | function onReset(event) { // 'this' is the form element 89 | var $form = $(this), 90 | key = '__jquery_unobtrusive_validation_form_reset'; 91 | if ($form.data(key)) { 92 | return; 93 | } 94 | // Set a flag that indicates we're currently resetting the form. 95 | $form.data(key, true); 96 | try { 97 | $form.data("validator").resetForm(); 98 | } finally { 99 | $form.removeData(key); 100 | } 101 | 102 | $form.find(".validation-summary-errors") 103 | .addClass("validation-summary-valid") 104 | .removeClass("validation-summary-errors"); 105 | $form.find(".field-validation-error") 106 | .addClass("field-validation-valid") 107 | .removeClass("field-validation-error") 108 | .removeData("unobtrusiveContainer") 109 | .find(">*") // If we were using valmsg-replace, get the underlying error 110 | .removeData("unobtrusiveContainer"); 111 | } 112 | 113 | function validationInfo(form) { 114 | var $form = $(form), 115 | result = $form.data(data_validation), 116 | onResetProxy = $.proxy(onReset, form), 117 | defaultOptions = $jQval.unobtrusive.options || {}, 118 | execInContext = function (name, args) { 119 | var func = defaultOptions[name]; 120 | func && $.isFunction(func) && func.apply(form, args); 121 | } 122 | 123 | if (!result) { 124 | result = { 125 | options: { // options structure passed to jQuery Validate's validate() method 126 | errorClass: defaultOptions.errorClass || "input-validation-error", 127 | errorElement: defaultOptions.errorElement || "span", 128 | errorPlacement: function () { 129 | onError.apply(form, arguments); 130 | execInContext("errorPlacement", arguments); 131 | }, 132 | invalidHandler: function () { 133 | onErrors.apply(form, arguments); 134 | execInContext("invalidHandler", arguments); 135 | }, 136 | messages: {}, 137 | rules: {}, 138 | success: function () { 139 | onSuccess.apply(form, arguments); 140 | execInContext("success", arguments); 141 | } 142 | }, 143 | attachValidation: function () { 144 | $form 145 | .off("reset." + data_validation, onResetProxy) 146 | .on("reset." + data_validation, onResetProxy) 147 | .validate(this.options); 148 | }, 149 | validate: function () { // a validation function that is called by unobtrusive Ajax 150 | $form.validate(); 151 | return $form.valid(); 152 | } 153 | }; 154 | $form.data(data_validation, result); 155 | } 156 | 157 | return result; 158 | } 159 | 160 | $jQval.unobtrusive = { 161 | adapters: [], 162 | 163 | parseElement: function (element, skipAttach) { 164 | /// 165 | /// Parses a single HTML element for unobtrusive validation attributes. 166 | /// 167 | /// The HTML element to be parsed. 168 | /// [Optional] true to skip attaching the 169 | /// validation to the form. If parsing just this single element, you should specify true. 170 | /// If parsing several elements, you should specify false, and manually attach the validation 171 | /// to the form when you are finished. The default is false. 172 | var $element = $(element), 173 | form = $element.parents("form")[0], 174 | valInfo, rules, messages; 175 | 176 | if (!form) { // Cannot do client-side validation without a form 177 | return; 178 | } 179 | 180 | valInfo = validationInfo(form); 181 | valInfo.options.rules[element.name] = rules = {}; 182 | valInfo.options.messages[element.name] = messages = {}; 183 | 184 | $.each(this.adapters, function () { 185 | var prefix = "data-val-" + this.name, 186 | message = $element.attr(prefix), 187 | paramValues = {}; 188 | 189 | if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy) 190 | prefix += "-"; 191 | 192 | $.each(this.params, function () { 193 | paramValues[this] = $element.attr(prefix + this); 194 | }); 195 | 196 | this.adapt({ 197 | element: element, 198 | form: form, 199 | message: message, 200 | params: paramValues, 201 | rules: rules, 202 | messages: messages 203 | }); 204 | } 205 | }); 206 | 207 | $.extend(rules, { "__dummy__": true }); 208 | 209 | if (!skipAttach) { 210 | valInfo.attachValidation(); 211 | } 212 | }, 213 | 214 | parse: function (selector) { 215 | /// 216 | /// Parses all the HTML elements in the specified selector. It looks for input elements decorated 217 | /// with the [data-val=true] attribute value and enables validation according to the data-val-* 218 | /// attribute values. 219 | /// 220 | /// Any valid jQuery selector. 221 | 222 | // $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one 223 | // element with data-val=true 224 | var $selector = $(selector), 225 | $forms = $selector.parents() 226 | .addBack() 227 | .filter("form") 228 | .add($selector.find("form")) 229 | .has("[data-val=true]"); 230 | 231 | $selector.find("[data-val=true]").each(function () { 232 | $jQval.unobtrusive.parseElement(this, true); 233 | }); 234 | 235 | $forms.each(function () { 236 | var info = validationInfo(this); 237 | if (info) { 238 | info.attachValidation(); 239 | } 240 | }); 241 | } 242 | }; 243 | 244 | adapters = $jQval.unobtrusive.adapters; 245 | 246 | adapters.add = function (adapterName, params, fn) { 247 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation. 248 | /// The name of the adapter to be added. This matches the name used 249 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). 250 | /// [Optional] An array of parameter names (strings) that will 251 | /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and 252 | /// mmmm is the parameter name). 253 | /// The function to call, which adapts the values from the HTML 254 | /// attributes into jQuery Validate rules and/or messages. 255 | /// 256 | if (!fn) { // Called with no params, just a function 257 | fn = params; 258 | params = []; 259 | } 260 | this.push({ name: adapterName, params: params, adapt: fn }); 261 | return this; 262 | }; 263 | 264 | adapters.addBool = function (adapterName, ruleName) { 265 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where 266 | /// the jQuery Validate validation rule has no parameter values. 267 | /// The name of the adapter to be added. This matches the name used 268 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). 269 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value 270 | /// of adapterName will be used instead. 271 | /// 272 | return this.add(adapterName, function (options) { 273 | setValidationValues(options, ruleName || adapterName, true); 274 | }); 275 | }; 276 | 277 | adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) { 278 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where 279 | /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and 280 | /// one for min-and-max). The HTML parameters are expected to be named -min and -max. 281 | /// The name of the adapter to be added. This matches the name used 282 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). 283 | /// The name of the jQuery Validate rule to be used when you only 284 | /// have a minimum value. 285 | /// The name of the jQuery Validate rule to be used when you only 286 | /// have a maximum value. 287 | /// The name of the jQuery Validate rule to be used when you 288 | /// have both a minimum and maximum value. 289 | /// [Optional] The name of the HTML attribute that 290 | /// contains the minimum value. The default is "min". 291 | /// [Optional] The name of the HTML attribute that 292 | /// contains the maximum value. The default is "max". 293 | /// 294 | return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) { 295 | var min = options.params.min, 296 | max = options.params.max; 297 | 298 | if (min && max) { 299 | setValidationValues(options, minMaxRuleName, [min, max]); 300 | } 301 | else if (min) { 302 | setValidationValues(options, minRuleName, min); 303 | } 304 | else if (max) { 305 | setValidationValues(options, maxRuleName, max); 306 | } 307 | }); 308 | }; 309 | 310 | adapters.addSingleVal = function (adapterName, attribute, ruleName) { 311 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where 312 | /// the jQuery Validate validation rule has a single value. 313 | /// The name of the adapter to be added. This matches the name used 314 | /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name). 315 | /// [Optional] The name of the HTML attribute that contains the value. 316 | /// The default is "val". 317 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value 318 | /// of adapterName will be used instead. 319 | /// 320 | return this.add(adapterName, [attribute || "val"], function (options) { 321 | setValidationValues(options, ruleName || adapterName, options.params[attribute]); 322 | }); 323 | }; 324 | 325 | $jQval.addMethod("__dummy__", function (value, element, params) { 326 | return true; 327 | }); 328 | 329 | $jQval.addMethod("regex", function (value, element, params) { 330 | var match; 331 | if (this.optional(element)) { 332 | return true; 333 | } 334 | 335 | match = new RegExp(params).exec(value); 336 | return (match && (match.index === 0) && (match[0].length === value.length)); 337 | }); 338 | 339 | $jQval.addMethod("nonalphamin", function (value, element, nonalphamin) { 340 | var match; 341 | if (nonalphamin) { 342 | match = value.match(/\W/g); 343 | match = match && match.length >= nonalphamin; 344 | } 345 | return match; 346 | }); 347 | 348 | if ($jQval.methods.extension) { 349 | adapters.addSingleVal("accept", "mimtype"); 350 | adapters.addSingleVal("extension", "extension"); 351 | } else { 352 | // for backward compatibility, when the 'extension' validation method does not exist, such as with versions 353 | // of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for 354 | // validating the extension, and ignore mime-type validations as they are not supported. 355 | adapters.addSingleVal("extension", "extension", "accept"); 356 | } 357 | 358 | adapters.addSingleVal("regex", "pattern"); 359 | adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"); 360 | adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range"); 361 | adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength"); 362 | adapters.add("equalto", ["other"], function (options) { 363 | var prefix = getModelPrefix(options.element.name), 364 | other = options.params.other, 365 | fullOtherName = appendModelPrefix(other, prefix), 366 | element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0]; 367 | 368 | setValidationValues(options, "equalTo", element); 369 | }); 370 | adapters.add("required", function (options) { 371 | // jQuery Validate equates "required" with "mandatory" for checkbox elements 372 | if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") { 373 | setValidationValues(options, "required", true); 374 | } 375 | }); 376 | adapters.add("remote", ["url", "type", "additionalfields"], function (options) { 377 | var value = { 378 | url: options.params.url, 379 | type: options.params.type || "GET", 380 | data: {} 381 | }, 382 | prefix = getModelPrefix(options.element.name); 383 | 384 | $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) { 385 | var paramName = appendModelPrefix(fieldName, prefix); 386 | value.data[paramName] = function () { 387 | var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']"); 388 | // For checkboxes and radio buttons, only pick up values from checked fields. 389 | if (field.is(":checkbox")) { 390 | return field.filter(":checked").val() || field.filter(":hidden").val() || ''; 391 | } 392 | else if (field.is(":radio")) { 393 | return field.filter(":checked").val() || ''; 394 | } 395 | return field.val(); 396 | }; 397 | }); 398 | 399 | setValidationValues(options, "remote", value); 400 | }); 401 | adapters.add("password", ["min", "nonalphamin", "regex"], function (options) { 402 | if (options.params.min) { 403 | setValidationValues(options, "minlength", options.params.min); 404 | } 405 | if (options.params.nonalphamin) { 406 | setValidationValues(options, "nonalphamin", options.params.nonalphamin); 407 | } 408 | if (options.params.regex) { 409 | setValidationValues(options, "regex", options.params.regex); 410 | } 411 | }); 412 | 413 | $(function () { 414 | $jQval.unobtrusive.parse(document); 415 | }); 416 | }(jQuery)); -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":";;;;AAmBA,YAAA,aAAA,UAAA,aAAA,aAAA,aAME,YAAA,EAAA,KAAA,EAAA,eC2CA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBDvCR,mBAAA,mBAAA,oBAAA,oBAAA,iBAAA,iBAAA,oBAAA,oBAAA,oBAAA,oBAAA,oBAAA,oBCsCA,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBDlCR,qBAAA,sBAAA,sBAAA,uBAAA,mBAAA,oBAAA,sBAAA,uBAAA,sBAAA,uBAAA,sBAAA,uBAAA,+BAAA,gCAAA,6BAAA,gCAAA,gCAAA,gCCiCA,mBAAA,KACQ,WAAA,KDlDV,mBAAA,oBAAA,iBAAA,oBAAA,oBAAA,oBAuBI,YAAA,KAyCF,YAAA,YAEE,iBAAA,KAKJ,aErEI,YAAA,EAAA,IAAA,EAAA,KACA,iBAAA,iDACA,iBAAA,4CAAA,iBAAA,qEAEA,iBAAA,+CCnBF,OAAA,+GH4CA,OAAA,0DACA,kBAAA,SAuC2C,aAAA,QAA2B,aAAA,KArCtE,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAgBN,aEtEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAiBN,aEvEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAkBN,UExEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,gBAAA,gBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,iBAAA,iBAEE,iBAAA,QACA,aAAA,QAMA,mBAAA,0BAAA,yBAAA,0BAAA,yBAAA,yBAAA,oBAAA,2BAAA,0BAAA,2BAAA,0BAAA,0BAAA,6BAAA,oCAAA,mCAAA,oCAAA,mCAAA,mCAME,iBAAA,QACA,iBAAA,KAmBN,aEzEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAoBN,YE1EI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,kBAAA,kBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,mBAAA,mBAEE,iBAAA,QACA,aAAA,QAMA,qBAAA,4BAAA,2BAAA,4BAAA,2BAAA,2BAAA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,+BAAA,sCAAA,qCAAA,sCAAA,qCAAA,qCAME,iBAAA,QACA,iBAAA,KA2BN,eAAA,WClCE,mBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,EAAA,IAAA,IAAA,iBD2CV,0BAAA,0BE3FI,iBAAA,QACA,iBAAA,oDACA,iBAAA,+CAAA,iBAAA,wEACA,iBAAA,kDACA,OAAA,+GF0FF,kBAAA,SAEF,yBAAA,+BAAA,+BEhGI,iBAAA,QACA,iBAAA,oDACA,iBAAA,+CAAA,iBAAA,wEACA,iBAAA,kDACA,OAAA,+GFgGF,kBAAA,SASF,gBE7GI,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GACA,OAAA,0DCnBF,kBAAA,SH+HA,cAAA,ICjEA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBD6DV,sCAAA,oCE7GI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SD2CF,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBD0EV,cAAA,iBAEE,YAAA,EAAA,IAAA,EAAA,sBAIF,gBEhII,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GACA,OAAA,0DCnBF,kBAAA,SHkJA,cAAA,IAHF,sCAAA,oCEhII,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SD2CF,mBAAA,MAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBDgFV,8BAAA,iCAYI,YAAA,EAAA,KAAA,EAAA,gBAKJ,qBAAA,kBAAA,mBAGE,cAAA,EAqBF,yBAfI,mDAAA,yDAAA,yDAGE,MAAA,KE7JF,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,UFqKJ,OACE,YAAA,EAAA,IAAA,EAAA,qBC3HA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,gBDsIV,eEtLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAKF,YEvLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAMF,eExLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAOF,cEzLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAeF,UEjMI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFuMJ,cE3MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFwMJ,sBE5MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFyMJ,mBE7MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF0MJ,sBE9MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF2MJ,qBE/MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF+MJ,sBElLI,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKFyLJ,YACE,cAAA,IC9KA,mBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,EAAA,IAAA,IAAA,iBDgLV,wBAAA,8BAAA,8BAGE,YAAA,EAAA,KAAA,EAAA,QEnOE,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFiOF,aAAA,QALF,+BAAA,qCAAA,qCAQI,YAAA,KAUJ,OCnME,mBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,EAAA,IAAA,IAAA,gBD4MV,8BE5PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFyPJ,8BE7PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF0PJ,8BE9PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF2PJ,2BE/PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF4PJ,8BEhQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF6PJ,6BEjQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFoQJ,MExQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFsQF,aAAA,QC3NA,mBAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,EAAA,IAAA,EAAA,qBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,EAAA,IAAA,EAAA","sourcesContent":["/*!\n * Bootstrap v3.3.7 (http://getbootstrap.com)\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n .box-shadow(none);\n }\n\n .badge {\n text-shadow: none;\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &.focus,\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257\n border-radius: @navbar-border-radius;\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n// Fix active state of dropdown items in collapsed mode\n@media (max-width: @grid-float-breakpoint-max) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: #fff;\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n }\n }\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n\n .badge {\n text-shadow: none;\n }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They have been removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility) {\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]} -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.7 (http://getbootstrap.com) 3 | * Copyright 2011-2016 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | .btn-default, 7 | .btn-primary, 8 | .btn-success, 9 | .btn-info, 10 | .btn-warning, 11 | .btn-danger { 12 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); 13 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 14 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 15 | } 16 | .btn-default:active, 17 | .btn-primary:active, 18 | .btn-success:active, 19 | .btn-info:active, 20 | .btn-warning:active, 21 | .btn-danger:active, 22 | .btn-default.active, 23 | .btn-primary.active, 24 | .btn-success.active, 25 | .btn-info.active, 26 | .btn-warning.active, 27 | .btn-danger.active { 28 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 29 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 30 | } 31 | .btn-default.disabled, 32 | .btn-primary.disabled, 33 | .btn-success.disabled, 34 | .btn-info.disabled, 35 | .btn-warning.disabled, 36 | .btn-danger.disabled, 37 | .btn-default[disabled], 38 | .btn-primary[disabled], 39 | .btn-success[disabled], 40 | .btn-info[disabled], 41 | .btn-warning[disabled], 42 | .btn-danger[disabled], 43 | fieldset[disabled] .btn-default, 44 | fieldset[disabled] .btn-primary, 45 | fieldset[disabled] .btn-success, 46 | fieldset[disabled] .btn-info, 47 | fieldset[disabled] .btn-warning, 48 | fieldset[disabled] .btn-danger { 49 | -webkit-box-shadow: none; 50 | box-shadow: none; 51 | } 52 | .btn-default .badge, 53 | .btn-primary .badge, 54 | .btn-success .badge, 55 | .btn-info .badge, 56 | .btn-warning .badge, 57 | .btn-danger .badge { 58 | text-shadow: none; 59 | } 60 | .btn:active, 61 | .btn.active { 62 | background-image: none; 63 | } 64 | .btn-default { 65 | text-shadow: 0 1px 0 #fff; 66 | background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); 67 | background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%); 68 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0)); 69 | background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); 70 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); 71 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 72 | background-repeat: repeat-x; 73 | border-color: #dbdbdb; 74 | border-color: #ccc; 75 | } 76 | .btn-default:hover, 77 | .btn-default:focus { 78 | background-color: #e0e0e0; 79 | background-position: 0 -15px; 80 | } 81 | .btn-default:active, 82 | .btn-default.active { 83 | background-color: #e0e0e0; 84 | border-color: #dbdbdb; 85 | } 86 | .btn-default.disabled, 87 | .btn-default[disabled], 88 | fieldset[disabled] .btn-default, 89 | .btn-default.disabled:hover, 90 | .btn-default[disabled]:hover, 91 | fieldset[disabled] .btn-default:hover, 92 | .btn-default.disabled:focus, 93 | .btn-default[disabled]:focus, 94 | fieldset[disabled] .btn-default:focus, 95 | .btn-default.disabled.focus, 96 | .btn-default[disabled].focus, 97 | fieldset[disabled] .btn-default.focus, 98 | .btn-default.disabled:active, 99 | .btn-default[disabled]:active, 100 | fieldset[disabled] .btn-default:active, 101 | .btn-default.disabled.active, 102 | .btn-default[disabled].active, 103 | fieldset[disabled] .btn-default.active { 104 | background-color: #e0e0e0; 105 | background-image: none; 106 | } 107 | .btn-primary { 108 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%); 109 | background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%); 110 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88)); 111 | background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%); 112 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0); 113 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 114 | background-repeat: repeat-x; 115 | border-color: #245580; 116 | } 117 | .btn-primary:hover, 118 | .btn-primary:focus { 119 | background-color: #265a88; 120 | background-position: 0 -15px; 121 | } 122 | .btn-primary:active, 123 | .btn-primary.active { 124 | background-color: #265a88; 125 | border-color: #245580; 126 | } 127 | .btn-primary.disabled, 128 | .btn-primary[disabled], 129 | fieldset[disabled] .btn-primary, 130 | .btn-primary.disabled:hover, 131 | .btn-primary[disabled]:hover, 132 | fieldset[disabled] .btn-primary:hover, 133 | .btn-primary.disabled:focus, 134 | .btn-primary[disabled]:focus, 135 | fieldset[disabled] .btn-primary:focus, 136 | .btn-primary.disabled.focus, 137 | .btn-primary[disabled].focus, 138 | fieldset[disabled] .btn-primary.focus, 139 | .btn-primary.disabled:active, 140 | .btn-primary[disabled]:active, 141 | fieldset[disabled] .btn-primary:active, 142 | .btn-primary.disabled.active, 143 | .btn-primary[disabled].active, 144 | fieldset[disabled] .btn-primary.active { 145 | background-color: #265a88; 146 | background-image: none; 147 | } 148 | .btn-success { 149 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); 150 | background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); 151 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); 152 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); 153 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); 154 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 155 | background-repeat: repeat-x; 156 | border-color: #3e8f3e; 157 | } 158 | .btn-success:hover, 159 | .btn-success:focus { 160 | background-color: #419641; 161 | background-position: 0 -15px; 162 | } 163 | .btn-success:active, 164 | .btn-success.active { 165 | background-color: #419641; 166 | border-color: #3e8f3e; 167 | } 168 | .btn-success.disabled, 169 | .btn-success[disabled], 170 | fieldset[disabled] .btn-success, 171 | .btn-success.disabled:hover, 172 | .btn-success[disabled]:hover, 173 | fieldset[disabled] .btn-success:hover, 174 | .btn-success.disabled:focus, 175 | .btn-success[disabled]:focus, 176 | fieldset[disabled] .btn-success:focus, 177 | .btn-success.disabled.focus, 178 | .btn-success[disabled].focus, 179 | fieldset[disabled] .btn-success.focus, 180 | .btn-success.disabled:active, 181 | .btn-success[disabled]:active, 182 | fieldset[disabled] .btn-success:active, 183 | .btn-success.disabled.active, 184 | .btn-success[disabled].active, 185 | fieldset[disabled] .btn-success.active { 186 | background-color: #419641; 187 | background-image: none; 188 | } 189 | .btn-info { 190 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 191 | background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 192 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); 193 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); 194 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); 195 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 196 | background-repeat: repeat-x; 197 | border-color: #28a4c9; 198 | } 199 | .btn-info:hover, 200 | .btn-info:focus { 201 | background-color: #2aabd2; 202 | background-position: 0 -15px; 203 | } 204 | .btn-info:active, 205 | .btn-info.active { 206 | background-color: #2aabd2; 207 | border-color: #28a4c9; 208 | } 209 | .btn-info.disabled, 210 | .btn-info[disabled], 211 | fieldset[disabled] .btn-info, 212 | .btn-info.disabled:hover, 213 | .btn-info[disabled]:hover, 214 | fieldset[disabled] .btn-info:hover, 215 | .btn-info.disabled:focus, 216 | .btn-info[disabled]:focus, 217 | fieldset[disabled] .btn-info:focus, 218 | .btn-info.disabled.focus, 219 | .btn-info[disabled].focus, 220 | fieldset[disabled] .btn-info.focus, 221 | .btn-info.disabled:active, 222 | .btn-info[disabled]:active, 223 | fieldset[disabled] .btn-info:active, 224 | .btn-info.disabled.active, 225 | .btn-info[disabled].active, 226 | fieldset[disabled] .btn-info.active { 227 | background-color: #2aabd2; 228 | background-image: none; 229 | } 230 | .btn-warning { 231 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 232 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 233 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); 234 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); 235 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); 236 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 237 | background-repeat: repeat-x; 238 | border-color: #e38d13; 239 | } 240 | .btn-warning:hover, 241 | .btn-warning:focus { 242 | background-color: #eb9316; 243 | background-position: 0 -15px; 244 | } 245 | .btn-warning:active, 246 | .btn-warning.active { 247 | background-color: #eb9316; 248 | border-color: #e38d13; 249 | } 250 | .btn-warning.disabled, 251 | .btn-warning[disabled], 252 | fieldset[disabled] .btn-warning, 253 | .btn-warning.disabled:hover, 254 | .btn-warning[disabled]:hover, 255 | fieldset[disabled] .btn-warning:hover, 256 | .btn-warning.disabled:focus, 257 | .btn-warning[disabled]:focus, 258 | fieldset[disabled] .btn-warning:focus, 259 | .btn-warning.disabled.focus, 260 | .btn-warning[disabled].focus, 261 | fieldset[disabled] .btn-warning.focus, 262 | .btn-warning.disabled:active, 263 | .btn-warning[disabled]:active, 264 | fieldset[disabled] .btn-warning:active, 265 | .btn-warning.disabled.active, 266 | .btn-warning[disabled].active, 267 | fieldset[disabled] .btn-warning.active { 268 | background-color: #eb9316; 269 | background-image: none; 270 | } 271 | .btn-danger { 272 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 273 | background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 274 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); 275 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); 276 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); 277 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 278 | background-repeat: repeat-x; 279 | border-color: #b92c28; 280 | } 281 | .btn-danger:hover, 282 | .btn-danger:focus { 283 | background-color: #c12e2a; 284 | background-position: 0 -15px; 285 | } 286 | .btn-danger:active, 287 | .btn-danger.active { 288 | background-color: #c12e2a; 289 | border-color: #b92c28; 290 | } 291 | .btn-danger.disabled, 292 | .btn-danger[disabled], 293 | fieldset[disabled] .btn-danger, 294 | .btn-danger.disabled:hover, 295 | .btn-danger[disabled]:hover, 296 | fieldset[disabled] .btn-danger:hover, 297 | .btn-danger.disabled:focus, 298 | .btn-danger[disabled]:focus, 299 | fieldset[disabled] .btn-danger:focus, 300 | .btn-danger.disabled.focus, 301 | .btn-danger[disabled].focus, 302 | fieldset[disabled] .btn-danger.focus, 303 | .btn-danger.disabled:active, 304 | .btn-danger[disabled]:active, 305 | fieldset[disabled] .btn-danger:active, 306 | .btn-danger.disabled.active, 307 | .btn-danger[disabled].active, 308 | fieldset[disabled] .btn-danger.active { 309 | background-color: #c12e2a; 310 | background-image: none; 311 | } 312 | .thumbnail, 313 | .img-thumbnail { 314 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 315 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 316 | } 317 | .dropdown-menu > li > a:hover, 318 | .dropdown-menu > li > a:focus { 319 | background-color: #e8e8e8; 320 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 321 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 322 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 323 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 324 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 325 | background-repeat: repeat-x; 326 | } 327 | .dropdown-menu > .active > a, 328 | .dropdown-menu > .active > a:hover, 329 | .dropdown-menu > .active > a:focus { 330 | background-color: #2e6da4; 331 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 332 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 333 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 334 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 335 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 336 | background-repeat: repeat-x; 337 | } 338 | .navbar-default { 339 | background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); 340 | background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%); 341 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8)); 342 | background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); 343 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 344 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 345 | background-repeat: repeat-x; 346 | border-radius: 4px; 347 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 348 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 349 | } 350 | .navbar-default .navbar-nav > .open > a, 351 | .navbar-default .navbar-nav > .active > a { 352 | background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 353 | background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 354 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2)); 355 | background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%); 356 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0); 357 | background-repeat: repeat-x; 358 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 359 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 360 | } 361 | .navbar-brand, 362 | .navbar-nav > li > a { 363 | text-shadow: 0 1px 0 rgba(255, 255, 255, .25); 364 | } 365 | .navbar-inverse { 366 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); 367 | background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%); 368 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222)); 369 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); 370 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 371 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 372 | background-repeat: repeat-x; 373 | border-radius: 4px; 374 | } 375 | .navbar-inverse .navbar-nav > .open > a, 376 | .navbar-inverse .navbar-nav > .active > a { 377 | background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%); 378 | background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%); 379 | background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f)); 380 | background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%); 381 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0); 382 | background-repeat: repeat-x; 383 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 384 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 385 | } 386 | .navbar-inverse .navbar-brand, 387 | .navbar-inverse .navbar-nav > li > a { 388 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); 389 | } 390 | .navbar-static-top, 391 | .navbar-fixed-top, 392 | .navbar-fixed-bottom { 393 | border-radius: 0; 394 | } 395 | @media (max-width: 767px) { 396 | .navbar .navbar-nav .open .dropdown-menu > .active > a, 397 | .navbar .navbar-nav .open .dropdown-menu > .active > a:hover, 398 | .navbar .navbar-nav .open .dropdown-menu > .active > a:focus { 399 | color: #fff; 400 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 401 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 402 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 403 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 404 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 405 | background-repeat: repeat-x; 406 | } 407 | } 408 | .alert { 409 | text-shadow: 0 1px 0 rgba(255, 255, 255, .2); 410 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 411 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 412 | } 413 | .alert-success { 414 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 415 | background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 416 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); 417 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 418 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 419 | background-repeat: repeat-x; 420 | border-color: #b2dba1; 421 | } 422 | .alert-info { 423 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 424 | background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 425 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); 426 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 427 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 428 | background-repeat: repeat-x; 429 | border-color: #9acfea; 430 | } 431 | .alert-warning { 432 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 433 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 434 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); 435 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 436 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 437 | background-repeat: repeat-x; 438 | border-color: #f5e79e; 439 | } 440 | .alert-danger { 441 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 442 | background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 443 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); 444 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 445 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 446 | background-repeat: repeat-x; 447 | border-color: #dca7a7; 448 | } 449 | .progress { 450 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 451 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 452 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); 453 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 454 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 455 | background-repeat: repeat-x; 456 | } 457 | .progress-bar { 458 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%); 459 | background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%); 460 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090)); 461 | background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%); 462 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0); 463 | background-repeat: repeat-x; 464 | } 465 | .progress-bar-success { 466 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 467 | background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); 468 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); 469 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 470 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 471 | background-repeat: repeat-x; 472 | } 473 | .progress-bar-info { 474 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 475 | background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 476 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); 477 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 478 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 479 | background-repeat: repeat-x; 480 | } 481 | .progress-bar-warning { 482 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 483 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 484 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); 485 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 486 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 487 | background-repeat: repeat-x; 488 | } 489 | .progress-bar-danger { 490 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 491 | background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); 492 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); 493 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 494 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 495 | background-repeat: repeat-x; 496 | } 497 | .progress-bar-striped { 498 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 499 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 500 | background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 501 | } 502 | .list-group { 503 | border-radius: 4px; 504 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 505 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 506 | } 507 | .list-group-item.active, 508 | .list-group-item.active:hover, 509 | .list-group-item.active:focus { 510 | text-shadow: 0 -1px 0 #286090; 511 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%); 512 | background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%); 513 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a)); 514 | background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%); 515 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0); 516 | background-repeat: repeat-x; 517 | border-color: #2b669a; 518 | } 519 | .list-group-item.active .badge, 520 | .list-group-item.active:hover .badge, 521 | .list-group-item.active:focus .badge { 522 | text-shadow: none; 523 | } 524 | .panel { 525 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 526 | box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 527 | } 528 | .panel-default > .panel-heading { 529 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 530 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 531 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 532 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 533 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 534 | background-repeat: repeat-x; 535 | } 536 | .panel-primary > .panel-heading { 537 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 538 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 539 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 540 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 541 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 542 | background-repeat: repeat-x; 543 | } 544 | .panel-success > .panel-heading { 545 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 546 | background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 547 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); 548 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 549 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 550 | background-repeat: repeat-x; 551 | } 552 | .panel-info > .panel-heading { 553 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 554 | background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 555 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); 556 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 557 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 558 | background-repeat: repeat-x; 559 | } 560 | .panel-warning > .panel-heading { 561 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 562 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 563 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); 564 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 565 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 566 | background-repeat: repeat-x; 567 | } 568 | .panel-danger > .panel-heading { 569 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 570 | background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 571 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); 572 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 573 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 574 | background-repeat: repeat-x; 575 | } 576 | .well { 577 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 578 | background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 579 | background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); 580 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 581 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 582 | background-repeat: repeat-x; 583 | border-color: #dcdcdc; 584 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 585 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 586 | } 587 | /*# sourceMappingURL=bootstrap-theme.css.map */ 588 | -------------------------------------------------------------------------------- /src/VstsDockerBuild.WebApp/wwwroot/lib/jquery-validation/dist/additional-methods.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Validation Plugin v1.14.0 3 | * 4 | * http://jqueryvalidation.org/ 5 | * 6 | * Copyright (c) 2015 Jörn Zaefferer 7 | * Released under the MIT license 8 | */ 9 | (function( factory ) { 10 | if ( typeof define === "function" && define.amd ) { 11 | define( ["jquery", "./jquery.validate"], factory ); 12 | } else { 13 | factory( jQuery ); 14 | } 15 | }(function( $ ) { 16 | 17 | (function() { 18 | 19 | function stripHtml(value) { 20 | // remove html tags and space chars 21 | return value.replace(/<.[^<>]*?>/g, " ").replace(/ | /gi, " ") 22 | // remove punctuation 23 | .replace(/[.(),;:!?%#$'\"_+=\/\-“”’]*/g, ""); 24 | } 25 | 26 | $.validator.addMethod("maxWords", function(value, element, params) { 27 | return this.optional(element) || stripHtml(value).match(/\b\w+\b/g).length <= params; 28 | }, $.validator.format("Please enter {0} words or less.")); 29 | 30 | $.validator.addMethod("minWords", function(value, element, params) { 31 | return this.optional(element) || stripHtml(value).match(/\b\w+\b/g).length >= params; 32 | }, $.validator.format("Please enter at least {0} words.")); 33 | 34 | $.validator.addMethod("rangeWords", function(value, element, params) { 35 | var valueStripped = stripHtml(value), 36 | regex = /\b\w+\b/g; 37 | return this.optional(element) || valueStripped.match(regex).length >= params[0] && valueStripped.match(regex).length <= params[1]; 38 | }, $.validator.format("Please enter between {0} and {1} words.")); 39 | 40 | }()); 41 | 42 | // Accept a value from a file input based on a required mimetype 43 | $.validator.addMethod("accept", function(value, element, param) { 44 | // Split mime on commas in case we have multiple types we can accept 45 | var typeParam = typeof param === "string" ? param.replace(/\s/g, "").replace(/,/g, "|") : "image/*", 46 | optionalValue = this.optional(element), 47 | i, file; 48 | 49 | // Element is optional 50 | if (optionalValue) { 51 | return optionalValue; 52 | } 53 | 54 | if ($(element).attr("type") === "file") { 55 | // If we are using a wildcard, make it regex friendly 56 | typeParam = typeParam.replace(/\*/g, ".*"); 57 | 58 | // Check if the element has a FileList before checking each file 59 | if (element.files && element.files.length) { 60 | for (i = 0; i < element.files.length; i++) { 61 | file = element.files[i]; 62 | 63 | // Grab the mimetype from the loaded file, verify it matches 64 | if (!file.type.match(new RegExp( "\\.?(" + typeParam + ")$", "i"))) { 65 | return false; 66 | } 67 | } 68 | } 69 | } 70 | 71 | // Either return true because we've validated each file, or because the 72 | // browser does not support element.files and the FileList feature 73 | return true; 74 | }, $.validator.format("Please enter a value with a valid mimetype.")); 75 | 76 | $.validator.addMethod("alphanumeric", function(value, element) { 77 | return this.optional(element) || /^\w+$/i.test(value); 78 | }, "Letters, numbers, and underscores only please"); 79 | 80 | /* 81 | * Dutch bank account numbers (not 'giro' numbers) have 9 digits 82 | * and pass the '11 check'. 83 | * We accept the notation with spaces, as that is common. 84 | * acceptable: 123456789 or 12 34 56 789 85 | */ 86 | $.validator.addMethod("bankaccountNL", function(value, element) { 87 | if (this.optional(element)) { 88 | return true; 89 | } 90 | if (!(/^[0-9]{9}|([0-9]{2} ){3}[0-9]{3}$/.test(value))) { 91 | return false; 92 | } 93 | // now '11 check' 94 | var account = value.replace(/ /g, ""), // remove spaces 95 | sum = 0, 96 | len = account.length, 97 | pos, factor, digit; 98 | for ( pos = 0; pos < len; pos++ ) { 99 | factor = len - pos; 100 | digit = account.substring(pos, pos + 1); 101 | sum = sum + factor * digit; 102 | } 103 | return sum % 11 === 0; 104 | }, "Please specify a valid bank account number"); 105 | 106 | $.validator.addMethod("bankorgiroaccountNL", function(value, element) { 107 | return this.optional(element) || 108 | ($.validator.methods.bankaccountNL.call(this, value, element)) || 109 | ($.validator.methods.giroaccountNL.call(this, value, element)); 110 | }, "Please specify a valid bank or giro account number"); 111 | 112 | /** 113 | * BIC is the business identifier code (ISO 9362). This BIC check is not a guarantee for authenticity. 114 | * 115 | * BIC pattern: BBBBCCLLbbb (8 or 11 characters long; bbb is optional) 116 | * 117 | * BIC definition in detail: 118 | * - First 4 characters - bank code (only letters) 119 | * - Next 2 characters - ISO 3166-1 alpha-2 country code (only letters) 120 | * - Next 2 characters - location code (letters and digits) 121 | * a. shall not start with '0' or '1' 122 | * b. second character must be a letter ('O' is not allowed) or one of the following digits ('0' for test (therefore not allowed), '1' for passive participant and '2' for active participant) 123 | * - Last 3 characters - branch code, optional (shall not start with 'X' except in case of 'XXX' for primary office) (letters and digits) 124 | */ 125 | $.validator.addMethod("bic", function(value, element) { 126 | return this.optional( element ) || /^([A-Z]{6}[A-Z2-9][A-NP-Z1-2])(X{3}|[A-WY-Z0-9][A-Z0-9]{2})?$/.test( value ); 127 | }, "Please specify a valid BIC code"); 128 | 129 | /* 130 | * Código de identificación fiscal ( CIF ) is the tax identification code for Spanish legal entities 131 | * Further rules can be found in Spanish on http://es.wikipedia.org/wiki/C%C3%B3digo_de_identificaci%C3%B3n_fiscal 132 | */ 133 | $.validator.addMethod( "cifES", function( value ) { 134 | "use strict"; 135 | 136 | var num = [], 137 | controlDigit, sum, i, count, tmp, secondDigit; 138 | 139 | value = value.toUpperCase(); 140 | 141 | // Quick format test 142 | if ( !value.match( "((^[A-Z]{1}[0-9]{7}[A-Z0-9]{1}$|^[T]{1}[A-Z0-9]{8}$)|^[0-9]{8}[A-Z]{1}$)" ) ) { 143 | return false; 144 | } 145 | 146 | for ( i = 0; i < 9; i++ ) { 147 | num[ i ] = parseInt( value.charAt( i ), 10 ); 148 | } 149 | 150 | // Algorithm for checking CIF codes 151 | sum = num[ 2 ] + num[ 4 ] + num[ 6 ]; 152 | for ( count = 1; count < 8; count += 2 ) { 153 | tmp = ( 2 * num[ count ] ).toString(); 154 | secondDigit = tmp.charAt( 1 ); 155 | 156 | sum += parseInt( tmp.charAt( 0 ), 10 ) + ( secondDigit === "" ? 0 : parseInt( secondDigit, 10 ) ); 157 | } 158 | 159 | /* The first (position 1) is a letter following the following criteria: 160 | * A. Corporations 161 | * B. LLCs 162 | * C. General partnerships 163 | * D. Companies limited partnerships 164 | * E. Communities of goods 165 | * F. Cooperative Societies 166 | * G. Associations 167 | * H. Communities of homeowners in horizontal property regime 168 | * J. Civil Societies 169 | * K. Old format 170 | * L. Old format 171 | * M. Old format 172 | * N. Nonresident entities 173 | * P. Local authorities 174 | * Q. Autonomous bodies, state or not, and the like, and congregations and religious institutions 175 | * R. Congregations and religious institutions (since 2008 ORDER EHA/451/2008) 176 | * S. Organs of State Administration and regions 177 | * V. Agrarian Transformation 178 | * W. Permanent establishments of non-resident in Spain 179 | */ 180 | if ( /^[ABCDEFGHJNPQRSUVW]{1}/.test( value ) ) { 181 | sum += ""; 182 | controlDigit = 10 - parseInt( sum.charAt( sum.length - 1 ), 10 ); 183 | value += controlDigit; 184 | return ( num[ 8 ].toString() === String.fromCharCode( 64 + controlDigit ) || num[ 8 ].toString() === value.charAt( value.length - 1 ) ); 185 | } 186 | 187 | return false; 188 | 189 | }, "Please specify a valid CIF number." ); 190 | 191 | /* 192 | * Brazillian CPF number (Cadastrado de Pessoas Físicas) is the equivalent of a Brazilian tax registration number. 193 | * CPF numbers have 11 digits in total: 9 numbers followed by 2 check numbers that are being used for validation. 194 | */ 195 | $.validator.addMethod("cpfBR", function(value) { 196 | // Removing special characters from value 197 | value = value.replace(/([~!@#$%^&*()_+=`{}\[\]\-|\\:;'<>,.\/? ])+/g, ""); 198 | 199 | // Checking value to have 11 digits only 200 | if (value.length !== 11) { 201 | return false; 202 | } 203 | 204 | var sum = 0, 205 | firstCN, secondCN, checkResult, i; 206 | 207 | firstCN = parseInt(value.substring(9, 10), 10); 208 | secondCN = parseInt(value.substring(10, 11), 10); 209 | 210 | checkResult = function(sum, cn) { 211 | var result = (sum * 10) % 11; 212 | if ((result === 10) || (result === 11)) {result = 0;} 213 | return (result === cn); 214 | }; 215 | 216 | // Checking for dump data 217 | if (value === "" || 218 | value === "00000000000" || 219 | value === "11111111111" || 220 | value === "22222222222" || 221 | value === "33333333333" || 222 | value === "44444444444" || 223 | value === "55555555555" || 224 | value === "66666666666" || 225 | value === "77777777777" || 226 | value === "88888888888" || 227 | value === "99999999999" 228 | ) { 229 | return false; 230 | } 231 | 232 | // Step 1 - using first Check Number: 233 | for ( i = 1; i <= 9; i++ ) { 234 | sum = sum + parseInt(value.substring(i - 1, i), 10) * (11 - i); 235 | } 236 | 237 | // If first Check Number (CN) is valid, move to Step 2 - using second Check Number: 238 | if ( checkResult(sum, firstCN) ) { 239 | sum = 0; 240 | for ( i = 1; i <= 10; i++ ) { 241 | sum = sum + parseInt(value.substring(i - 1, i), 10) * (12 - i); 242 | } 243 | return checkResult(sum, secondCN); 244 | } 245 | return false; 246 | 247 | }, "Please specify a valid CPF number"); 248 | 249 | /* NOTICE: Modified version of Castle.Components.Validator.CreditCardValidator 250 | * Redistributed under the the Apache License 2.0 at http://www.apache.org/licenses/LICENSE-2.0 251 | * Valid Types: mastercard, visa, amex, dinersclub, enroute, discover, jcb, unknown, all (overrides all other settings) 252 | */ 253 | $.validator.addMethod("creditcardtypes", function(value, element, param) { 254 | if (/[^0-9\-]+/.test(value)) { 255 | return false; 256 | } 257 | 258 | value = value.replace(/\D/g, ""); 259 | 260 | var validTypes = 0x0000; 261 | 262 | if (param.mastercard) { 263 | validTypes |= 0x0001; 264 | } 265 | if (param.visa) { 266 | validTypes |= 0x0002; 267 | } 268 | if (param.amex) { 269 | validTypes |= 0x0004; 270 | } 271 | if (param.dinersclub) { 272 | validTypes |= 0x0008; 273 | } 274 | if (param.enroute) { 275 | validTypes |= 0x0010; 276 | } 277 | if (param.discover) { 278 | validTypes |= 0x0020; 279 | } 280 | if (param.jcb) { 281 | validTypes |= 0x0040; 282 | } 283 | if (param.unknown) { 284 | validTypes |= 0x0080; 285 | } 286 | if (param.all) { 287 | validTypes = 0x0001 | 0x0002 | 0x0004 | 0x0008 | 0x0010 | 0x0020 | 0x0040 | 0x0080; 288 | } 289 | if (validTypes & 0x0001 && /^(5[12345])/.test(value)) { //mastercard 290 | return value.length === 16; 291 | } 292 | if (validTypes & 0x0002 && /^(4)/.test(value)) { //visa 293 | return value.length === 16; 294 | } 295 | if (validTypes & 0x0004 && /^(3[47])/.test(value)) { //amex 296 | return value.length === 15; 297 | } 298 | if (validTypes & 0x0008 && /^(3(0[012345]|[68]))/.test(value)) { //dinersclub 299 | return value.length === 14; 300 | } 301 | if (validTypes & 0x0010 && /^(2(014|149))/.test(value)) { //enroute 302 | return value.length === 15; 303 | } 304 | if (validTypes & 0x0020 && /^(6011)/.test(value)) { //discover 305 | return value.length === 16; 306 | } 307 | if (validTypes & 0x0040 && /^(3)/.test(value)) { //jcb 308 | return value.length === 16; 309 | } 310 | if (validTypes & 0x0040 && /^(2131|1800)/.test(value)) { //jcb 311 | return value.length === 15; 312 | } 313 | if (validTypes & 0x0080) { //unknown 314 | return true; 315 | } 316 | return false; 317 | }, "Please enter a valid credit card number."); 318 | 319 | /** 320 | * Validates currencies with any given symbols by @jameslouiz 321 | * Symbols can be optional or required. Symbols required by default 322 | * 323 | * Usage examples: 324 | * currency: ["£", false] - Use false for soft currency validation 325 | * currency: ["$", false] 326 | * currency: ["RM", false] - also works with text based symbols such as "RM" - Malaysia Ringgit etc 327 | * 328 | * 329 | * 330 | * Soft symbol checking 331 | * currencyInput: { 332 | * currency: ["$", false] 333 | * } 334 | * 335 | * Strict symbol checking (default) 336 | * currencyInput: { 337 | * currency: "$" 338 | * //OR 339 | * currency: ["$", true] 340 | * } 341 | * 342 | * Multiple Symbols 343 | * currencyInput: { 344 | * currency: "$,£,¢" 345 | * } 346 | */ 347 | $.validator.addMethod("currency", function(value, element, param) { 348 | var isParamString = typeof param === "string", 349 | symbol = isParamString ? param : param[0], 350 | soft = isParamString ? true : param[1], 351 | regex; 352 | 353 | symbol = symbol.replace(/,/g, ""); 354 | symbol = soft ? symbol + "]" : symbol + "]?"; 355 | regex = "^[" + symbol + "([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)$"; 356 | regex = new RegExp(regex); 357 | return this.optional(element) || regex.test(value); 358 | 359 | }, "Please specify a valid currency"); 360 | 361 | $.validator.addMethod("dateFA", function(value, element) { 362 | return this.optional(element) || /^[1-4]\d{3}\/((0?[1-6]\/((3[0-1])|([1-2][0-9])|(0?[1-9])))|((1[0-2]|(0?[7-9]))\/(30|([1-2][0-9])|(0?[1-9]))))$/.test(value); 363 | }, $.validator.messages.date); 364 | 365 | /** 366 | * Return true, if the value is a valid date, also making this formal check dd/mm/yyyy. 367 | * 368 | * @example $.validator.methods.date("01/01/1900") 369 | * @result true 370 | * 371 | * @example $.validator.methods.date("01/13/1990") 372 | * @result false 373 | * 374 | * @example $.validator.methods.date("01.01.1900") 375 | * @result false 376 | * 377 | * @example 378 | * @desc Declares an optional input element whose value must be a valid date. 379 | * 380 | * @name $.validator.methods.dateITA 381 | * @type Boolean 382 | * @cat Plugins/Validate/Methods 383 | */ 384 | $.validator.addMethod("dateITA", function(value, element) { 385 | var check = false, 386 | re = /^\d{1,2}\/\d{1,2}\/\d{4}$/, 387 | adata, gg, mm, aaaa, xdata; 388 | if ( re.test(value)) { 389 | adata = value.split("/"); 390 | gg = parseInt(adata[0], 10); 391 | mm = parseInt(adata[1], 10); 392 | aaaa = parseInt(adata[2], 10); 393 | xdata = new Date(Date.UTC(aaaa, mm - 1, gg, 12, 0, 0, 0)); 394 | if ( ( xdata.getUTCFullYear() === aaaa ) && ( xdata.getUTCMonth () === mm - 1 ) && ( xdata.getUTCDate() === gg ) ) { 395 | check = true; 396 | } else { 397 | check = false; 398 | } 399 | } else { 400 | check = false; 401 | } 402 | return this.optional(element) || check; 403 | }, $.validator.messages.date); 404 | 405 | $.validator.addMethod("dateNL", function(value, element) { 406 | return this.optional(element) || /^(0?[1-9]|[12]\d|3[01])[\.\/\-](0?[1-9]|1[012])[\.\/\-]([12]\d)?(\d\d)$/.test(value); 407 | }, $.validator.messages.date); 408 | 409 | // Older "accept" file extension method. Old docs: http://docs.jquery.com/Plugins/Validation/Methods/accept 410 | $.validator.addMethod("extension", function(value, element, param) { 411 | param = typeof param === "string" ? param.replace(/,/g, "|") : "png|jpe?g|gif"; 412 | return this.optional(element) || value.match(new RegExp("\\.(" + param + ")$", "i")); 413 | }, $.validator.format("Please enter a value with a valid extension.")); 414 | 415 | /** 416 | * Dutch giro account numbers (not bank numbers) have max 7 digits 417 | */ 418 | $.validator.addMethod("giroaccountNL", function(value, element) { 419 | return this.optional(element) || /^[0-9]{1,7}$/.test(value); 420 | }, "Please specify a valid giro account number"); 421 | 422 | /** 423 | * IBAN is the international bank account number. 424 | * It has a country - specific format, that is checked here too 425 | */ 426 | $.validator.addMethod("iban", function(value, element) { 427 | // some quick simple tests to prevent needless work 428 | if (this.optional(element)) { 429 | return true; 430 | } 431 | 432 | // remove spaces and to upper case 433 | var iban = value.replace(/ /g, "").toUpperCase(), 434 | ibancheckdigits = "", 435 | leadingZeroes = true, 436 | cRest = "", 437 | cOperator = "", 438 | countrycode, ibancheck, charAt, cChar, bbanpattern, bbancountrypatterns, ibanregexp, i, p; 439 | 440 | // check the country code and find the country specific format 441 | countrycode = iban.substring(0, 2); 442 | bbancountrypatterns = { 443 | "AL": "\\d{8}[\\dA-Z]{16}", 444 | "AD": "\\d{8}[\\dA-Z]{12}", 445 | "AT": "\\d{16}", 446 | "AZ": "[\\dA-Z]{4}\\d{20}", 447 | "BE": "\\d{12}", 448 | "BH": "[A-Z]{4}[\\dA-Z]{14}", 449 | "BA": "\\d{16}", 450 | "BR": "\\d{23}[A-Z][\\dA-Z]", 451 | "BG": "[A-Z]{4}\\d{6}[\\dA-Z]{8}", 452 | "CR": "\\d{17}", 453 | "HR": "\\d{17}", 454 | "CY": "\\d{8}[\\dA-Z]{16}", 455 | "CZ": "\\d{20}", 456 | "DK": "\\d{14}", 457 | "DO": "[A-Z]{4}\\d{20}", 458 | "EE": "\\d{16}", 459 | "FO": "\\d{14}", 460 | "FI": "\\d{14}", 461 | "FR": "\\d{10}[\\dA-Z]{11}\\d{2}", 462 | "GE": "[\\dA-Z]{2}\\d{16}", 463 | "DE": "\\d{18}", 464 | "GI": "[A-Z]{4}[\\dA-Z]{15}", 465 | "GR": "\\d{7}[\\dA-Z]{16}", 466 | "GL": "\\d{14}", 467 | "GT": "[\\dA-Z]{4}[\\dA-Z]{20}", 468 | "HU": "\\d{24}", 469 | "IS": "\\d{22}", 470 | "IE": "[\\dA-Z]{4}\\d{14}", 471 | "IL": "\\d{19}", 472 | "IT": "[A-Z]\\d{10}[\\dA-Z]{12}", 473 | "KZ": "\\d{3}[\\dA-Z]{13}", 474 | "KW": "[A-Z]{4}[\\dA-Z]{22}", 475 | "LV": "[A-Z]{4}[\\dA-Z]{13}", 476 | "LB": "\\d{4}[\\dA-Z]{20}", 477 | "LI": "\\d{5}[\\dA-Z]{12}", 478 | "LT": "\\d{16}", 479 | "LU": "\\d{3}[\\dA-Z]{13}", 480 | "MK": "\\d{3}[\\dA-Z]{10}\\d{2}", 481 | "MT": "[A-Z]{4}\\d{5}[\\dA-Z]{18}", 482 | "MR": "\\d{23}", 483 | "MU": "[A-Z]{4}\\d{19}[A-Z]{3}", 484 | "MC": "\\d{10}[\\dA-Z]{11}\\d{2}", 485 | "MD": "[\\dA-Z]{2}\\d{18}", 486 | "ME": "\\d{18}", 487 | "NL": "[A-Z]{4}\\d{10}", 488 | "NO": "\\d{11}", 489 | "PK": "[\\dA-Z]{4}\\d{16}", 490 | "PS": "[\\dA-Z]{4}\\d{21}", 491 | "PL": "\\d{24}", 492 | "PT": "\\d{21}", 493 | "RO": "[A-Z]{4}[\\dA-Z]{16}", 494 | "SM": "[A-Z]\\d{10}[\\dA-Z]{12}", 495 | "SA": "\\d{2}[\\dA-Z]{18}", 496 | "RS": "\\d{18}", 497 | "SK": "\\d{20}", 498 | "SI": "\\d{15}", 499 | "ES": "\\d{20}", 500 | "SE": "\\d{20}", 501 | "CH": "\\d{5}[\\dA-Z]{12}", 502 | "TN": "\\d{20}", 503 | "TR": "\\d{5}[\\dA-Z]{17}", 504 | "AE": "\\d{3}\\d{16}", 505 | "GB": "[A-Z]{4}\\d{14}", 506 | "VG": "[\\dA-Z]{4}\\d{16}" 507 | }; 508 | 509 | bbanpattern = bbancountrypatterns[countrycode]; 510 | // As new countries will start using IBAN in the 511 | // future, we only check if the countrycode is known. 512 | // This prevents false negatives, while almost all 513 | // false positives introduced by this, will be caught 514 | // by the checksum validation below anyway. 515 | // Strict checking should return FALSE for unknown 516 | // countries. 517 | if (typeof bbanpattern !== "undefined") { 518 | ibanregexp = new RegExp("^[A-Z]{2}\\d{2}" + bbanpattern + "$", ""); 519 | if (!(ibanregexp.test(iban))) { 520 | return false; // invalid country specific format 521 | } 522 | } 523 | 524 | // now check the checksum, first convert to digits 525 | ibancheck = iban.substring(4, iban.length) + iban.substring(0, 4); 526 | for (i = 0; i < ibancheck.length; i++) { 527 | charAt = ibancheck.charAt(i); 528 | if (charAt !== "0") { 529 | leadingZeroes = false; 530 | } 531 | if (!leadingZeroes) { 532 | ibancheckdigits += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf(charAt); 533 | } 534 | } 535 | 536 | // calculate the result of: ibancheckdigits % 97 537 | for (p = 0; p < ibancheckdigits.length; p++) { 538 | cChar = ibancheckdigits.charAt(p); 539 | cOperator = "" + cRest + "" + cChar; 540 | cRest = cOperator % 97; 541 | } 542 | return cRest === 1; 543 | }, "Please specify a valid IBAN"); 544 | 545 | $.validator.addMethod("integer", function(value, element) { 546 | return this.optional(element) || /^-?\d+$/.test(value); 547 | }, "A positive or negative non-decimal number please"); 548 | 549 | $.validator.addMethod("ipv4", function(value, element) { 550 | return this.optional(element) || /^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/i.test(value); 551 | }, "Please enter a valid IP v4 address."); 552 | 553 | $.validator.addMethod("ipv6", function(value, element) { 554 | return this.optional(element) || /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i.test(value); 555 | }, "Please enter a valid IP v6 address."); 556 | 557 | $.validator.addMethod("lettersonly", function(value, element) { 558 | return this.optional(element) || /^[a-z]+$/i.test(value); 559 | }, "Letters only please"); 560 | 561 | $.validator.addMethod("letterswithbasicpunc", function(value, element) { 562 | return this.optional(element) || /^[a-z\-.,()'"\s]+$/i.test(value); 563 | }, "Letters or punctuation only please"); 564 | 565 | $.validator.addMethod("mobileNL", function(value, element) { 566 | return this.optional(element) || /^((\+|00(\s|\s?\-\s?)?)31(\s|\s?\-\s?)?(\(0\)[\-\s]?)?|0)6((\s|\s?\-\s?)?[0-9]){8}$/.test(value); 567 | }, "Please specify a valid mobile number"); 568 | 569 | /* For UK phone functions, do the following server side processing: 570 | * Compare original input with this RegEx pattern: 571 | * ^\(?(?:(?:00\)?[\s\-]?\(?|\+)(44)\)?[\s\-]?\(?(?:0\)?[\s\-]?\(?)?|0)([1-9]\d{1,4}\)?[\s\d\-]+)$ 572 | * Extract $1 and set $prefix to '+44' if $1 is '44', otherwise set $prefix to '0' 573 | * Extract $2 and remove hyphens, spaces and parentheses. Phone number is combined $prefix and $2. 574 | * A number of very detailed GB telephone number RegEx patterns can also be found at: 575 | * http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers 576 | */ 577 | $.validator.addMethod("mobileUK", function(phone_number, element) { 578 | phone_number = phone_number.replace(/\(|\)|\s+|-/g, ""); 579 | return this.optional(element) || phone_number.length > 9 && 580 | phone_number.match(/^(?:(?:(?:00\s?|\+)44\s?|0)7(?:[1345789]\d{2}|624)\s?\d{3}\s?\d{3})$/); 581 | }, "Please specify a valid mobile number"); 582 | 583 | /* 584 | * The número de identidad de extranjero ( NIE )is a code used to identify the non-nationals in Spain 585 | */ 586 | $.validator.addMethod( "nieES", function( value ) { 587 | "use strict"; 588 | 589 | value = value.toUpperCase(); 590 | 591 | // Basic format test 592 | if ( !value.match( "((^[A-Z]{1}[0-9]{7}[A-Z0-9]{1}$|^[T]{1}[A-Z0-9]{8}$)|^[0-9]{8}[A-Z]{1}$)" ) ) { 593 | return false; 594 | } 595 | 596 | // Test NIE 597 | //T 598 | if ( /^[T]{1}/.test( value ) ) { 599 | return ( value[ 8 ] === /^[T]{1}[A-Z0-9]{8}$/.test( value ) ); 600 | } 601 | 602 | //XYZ 603 | if ( /^[XYZ]{1}/.test( value ) ) { 604 | return ( 605 | value[ 8 ] === "TRWAGMYFPDXBNJZSQVHLCKE".charAt( 606 | value.replace( "X", "0" ) 607 | .replace( "Y", "1" ) 608 | .replace( "Z", "2" ) 609 | .substring( 0, 8 ) % 23 610 | ) 611 | ); 612 | } 613 | 614 | return false; 615 | 616 | }, "Please specify a valid NIE number." ); 617 | 618 | /* 619 | * The Número de Identificación Fiscal ( NIF ) is the way tax identification used in Spain for individuals 620 | */ 621 | $.validator.addMethod( "nifES", function( value ) { 622 | "use strict"; 623 | 624 | value = value.toUpperCase(); 625 | 626 | // Basic format test 627 | if ( !value.match("((^[A-Z]{1}[0-9]{7}[A-Z0-9]{1}$|^[T]{1}[A-Z0-9]{8}$)|^[0-9]{8}[A-Z]{1}$)") ) { 628 | return false; 629 | } 630 | 631 | // Test NIF 632 | if ( /^[0-9]{8}[A-Z]{1}$/.test( value ) ) { 633 | return ( "TRWAGMYFPDXBNJZSQVHLCKE".charAt( value.substring( 8, 0 ) % 23 ) === value.charAt( 8 ) ); 634 | } 635 | // Test specials NIF (starts with K, L or M) 636 | if ( /^[KLM]{1}/.test( value ) ) { 637 | return ( value[ 8 ] === String.fromCharCode( 64 ) ); 638 | } 639 | 640 | return false; 641 | 642 | }, "Please specify a valid NIF number." ); 643 | 644 | jQuery.validator.addMethod( "notEqualTo", function( value, element, param ) { 645 | return this.optional(element) || !$.validator.methods.equalTo.call( this, value, element, param ); 646 | }, "Please enter a different value, values must not be the same." ); 647 | 648 | $.validator.addMethod("nowhitespace", function(value, element) { 649 | return this.optional(element) || /^\S+$/i.test(value); 650 | }, "No white space please"); 651 | 652 | /** 653 | * Return true if the field value matches the given format RegExp 654 | * 655 | * @example $.validator.methods.pattern("AR1004",element,/^AR\d{4}$/) 656 | * @result true 657 | * 658 | * @example $.validator.methods.pattern("BR1004",element,/^AR\d{4}$/) 659 | * @result false 660 | * 661 | * @name $.validator.methods.pattern 662 | * @type Boolean 663 | * @cat Plugins/Validate/Methods 664 | */ 665 | $.validator.addMethod("pattern", function(value, element, param) { 666 | if (this.optional(element)) { 667 | return true; 668 | } 669 | if (typeof param === "string") { 670 | param = new RegExp("^(?:" + param + ")$"); 671 | } 672 | return param.test(value); 673 | }, "Invalid format."); 674 | 675 | /** 676 | * Dutch phone numbers have 10 digits (or 11 and start with +31). 677 | */ 678 | $.validator.addMethod("phoneNL", function(value, element) { 679 | return this.optional(element) || /^((\+|00(\s|\s?\-\s?)?)31(\s|\s?\-\s?)?(\(0\)[\-\s]?)?|0)[1-9]((\s|\s?\-\s?)?[0-9]){8}$/.test(value); 680 | }, "Please specify a valid phone number."); 681 | 682 | /* For UK phone functions, do the following server side processing: 683 | * Compare original input with this RegEx pattern: 684 | * ^\(?(?:(?:00\)?[\s\-]?\(?|\+)(44)\)?[\s\-]?\(?(?:0\)?[\s\-]?\(?)?|0)([1-9]\d{1,4}\)?[\s\d\-]+)$ 685 | * Extract $1 and set $prefix to '+44' if $1 is '44', otherwise set $prefix to '0' 686 | * Extract $2 and remove hyphens, spaces and parentheses. Phone number is combined $prefix and $2. 687 | * A number of very detailed GB telephone number RegEx patterns can also be found at: 688 | * http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers 689 | */ 690 | $.validator.addMethod("phoneUK", function(phone_number, element) { 691 | phone_number = phone_number.replace(/\(|\)|\s+|-/g, ""); 692 | return this.optional(element) || phone_number.length > 9 && 693 | phone_number.match(/^(?:(?:(?:00\s?|\+)44\s?)|(?:\(?0))(?:\d{2}\)?\s?\d{4}\s?\d{4}|\d{3}\)?\s?\d{3}\s?\d{3,4}|\d{4}\)?\s?(?:\d{5}|\d{3}\s?\d{3})|\d{5}\)?\s?\d{4,5})$/); 694 | }, "Please specify a valid phone number"); 695 | 696 | /** 697 | * matches US phone number format 698 | * 699 | * where the area code may not start with 1 and the prefix may not start with 1 700 | * allows '-' or ' ' as a separator and allows parens around area code 701 | * some people may want to put a '1' in front of their number 702 | * 703 | * 1(212)-999-2345 or 704 | * 212 999 2344 or 705 | * 212-999-0983 706 | * 707 | * but not 708 | * 111-123-5434 709 | * and not 710 | * 212 123 4567 711 | */ 712 | $.validator.addMethod("phoneUS", function(phone_number, element) { 713 | phone_number = phone_number.replace(/\s+/g, ""); 714 | return this.optional(element) || phone_number.length > 9 && 715 | phone_number.match(/^(\+?1-?)?(\([2-9]([02-9]\d|1[02-9])\)|[2-9]([02-9]\d|1[02-9]))-?[2-9]([02-9]\d|1[02-9])-?\d{4}$/); 716 | }, "Please specify a valid phone number"); 717 | 718 | /* For UK phone functions, do the following server side processing: 719 | * Compare original input with this RegEx pattern: 720 | * ^\(?(?:(?:00\)?[\s\-]?\(?|\+)(44)\)?[\s\-]?\(?(?:0\)?[\s\-]?\(?)?|0)([1-9]\d{1,4}\)?[\s\d\-]+)$ 721 | * Extract $1 and set $prefix to '+44' if $1 is '44', otherwise set $prefix to '0' 722 | * Extract $2 and remove hyphens, spaces and parentheses. Phone number is combined $prefix and $2. 723 | * A number of very detailed GB telephone number RegEx patterns can also be found at: 724 | * http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers 725 | */ 726 | //Matches UK landline + mobile, accepting only 01-3 for landline or 07 for mobile to exclude many premium numbers 727 | $.validator.addMethod("phonesUK", function(phone_number, element) { 728 | phone_number = phone_number.replace(/\(|\)|\s+|-/g, ""); 729 | return this.optional(element) || phone_number.length > 9 && 730 | phone_number.match(/^(?:(?:(?:00\s?|\+)44\s?|0)(?:1\d{8,9}|[23]\d{9}|7(?:[1345789]\d{8}|624\d{6})))$/); 731 | }, "Please specify a valid uk phone number"); 732 | 733 | /** 734 | * Matches a valid Canadian Postal Code 735 | * 736 | * @example jQuery.validator.methods.postalCodeCA( "H0H 0H0", element ) 737 | * @result true 738 | * 739 | * @example jQuery.validator.methods.postalCodeCA( "H0H0H0", element ) 740 | * @result false 741 | * 742 | * @name jQuery.validator.methods.postalCodeCA 743 | * @type Boolean 744 | * @cat Plugins/Validate/Methods 745 | */ 746 | $.validator.addMethod( "postalCodeCA", function( value, element ) { 747 | return this.optional( element ) || /^[ABCEGHJKLMNPRSTVXY]\d[A-Z] \d[A-Z]\d$/.test( value ); 748 | }, "Please specify a valid postal code" ); 749 | 750 | /* 751 | * Valida CEPs do brasileiros: 752 | * 753 | * Formatos aceitos: 754 | * 99999-999 755 | * 99.999-999 756 | * 99999999 757 | */ 758 | $.validator.addMethod("postalcodeBR", function(cep_value, element) { 759 | return this.optional(element) || /^\d{2}.\d{3}-\d{3}?$|^\d{5}-?\d{3}?$/.test( cep_value ); 760 | }, "Informe um CEP válido."); 761 | 762 | /* Matches Italian postcode (CAP) */ 763 | $.validator.addMethod("postalcodeIT", function(value, element) { 764 | return this.optional(element) || /^\d{5}$/.test(value); 765 | }, "Please specify a valid postal code"); 766 | 767 | $.validator.addMethod("postalcodeNL", function(value, element) { 768 | return this.optional(element) || /^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/.test(value); 769 | }, "Please specify a valid postal code"); 770 | 771 | // Matches UK postcode. Does not match to UK Channel Islands that have their own postcodes (non standard UK) 772 | $.validator.addMethod("postcodeUK", function(value, element) { 773 | return this.optional(element) || /^((([A-PR-UWYZ][0-9])|([A-PR-UWYZ][0-9][0-9])|([A-PR-UWYZ][A-HK-Y][0-9])|([A-PR-UWYZ][A-HK-Y][0-9][0-9])|([A-PR-UWYZ][0-9][A-HJKSTUW])|([A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRVWXY]))\s?([0-9][ABD-HJLNP-UW-Z]{2})|(GIR)\s?(0AA))$/i.test(value); 774 | }, "Please specify a valid UK postcode"); 775 | 776 | /* 777 | * Lets you say "at least X inputs that match selector Y must be filled." 778 | * 779 | * The end result is that neither of these inputs: 780 | * 781 | * 782 | * 783 | * 784 | * ...will validate unless at least one of them is filled. 785 | * 786 | * partnumber: {require_from_group: [1,".productinfo"]}, 787 | * description: {require_from_group: [1,".productinfo"]} 788 | * 789 | * options[0]: number of fields that must be filled in the group 790 | * options[1]: CSS selector that defines the group of conditionally required fields 791 | */ 792 | $.validator.addMethod("require_from_group", function(value, element, options) { 793 | var $fields = $(options[1], element.form), 794 | $fieldsFirst = $fields.eq(0), 795 | validator = $fieldsFirst.data("valid_req_grp") ? $fieldsFirst.data("valid_req_grp") : $.extend({}, this), 796 | isValid = $fields.filter(function() { 797 | return validator.elementValue(this); 798 | }).length >= options[0]; 799 | 800 | // Store the cloned validator for future validation 801 | $fieldsFirst.data("valid_req_grp", validator); 802 | 803 | // If element isn't being validated, run each require_from_group field's validation rules 804 | if (!$(element).data("being_validated")) { 805 | $fields.data("being_validated", true); 806 | $fields.each(function() { 807 | validator.element(this); 808 | }); 809 | $fields.data("being_validated", false); 810 | } 811 | return isValid; 812 | }, $.validator.format("Please fill at least {0} of these fields.")); 813 | 814 | /* 815 | * Lets you say "either at least X inputs that match selector Y must be filled, 816 | * OR they must all be skipped (left blank)." 817 | * 818 | * The end result, is that none of these inputs: 819 | * 820 | * 821 | * 822 | * 823 | * 824 | * ...will validate unless either at least two of them are filled, 825 | * OR none of them are. 826 | * 827 | * partnumber: {skip_or_fill_minimum: [2,".productinfo"]}, 828 | * description: {skip_or_fill_minimum: [2,".productinfo"]}, 829 | * color: {skip_or_fill_minimum: [2,".productinfo"]} 830 | * 831 | * options[0]: number of fields that must be filled in the group 832 | * options[1]: CSS selector that defines the group of conditionally required fields 833 | * 834 | */ 835 | $.validator.addMethod("skip_or_fill_minimum", function(value, element, options) { 836 | var $fields = $(options[1], element.form), 837 | $fieldsFirst = $fields.eq(0), 838 | validator = $fieldsFirst.data("valid_skip") ? $fieldsFirst.data("valid_skip") : $.extend({}, this), 839 | numberFilled = $fields.filter(function() { 840 | return validator.elementValue(this); 841 | }).length, 842 | isValid = numberFilled === 0 || numberFilled >= options[0]; 843 | 844 | // Store the cloned validator for future validation 845 | $fieldsFirst.data("valid_skip", validator); 846 | 847 | // If element isn't being validated, run each skip_or_fill_minimum field's validation rules 848 | if (!$(element).data("being_validated")) { 849 | $fields.data("being_validated", true); 850 | $fields.each(function() { 851 | validator.element(this); 852 | }); 853 | $fields.data("being_validated", false); 854 | } 855 | return isValid; 856 | }, $.validator.format("Please either skip these fields or fill at least {0} of them.")); 857 | 858 | /* Validates US States and/or Territories by @jdforsythe 859 | * Can be case insensitive or require capitalization - default is case insensitive 860 | * Can include US Territories or not - default does not 861 | * Can include US Military postal abbreviations (AA, AE, AP) - default does not 862 | * 863 | * Note: "States" always includes DC (District of Colombia) 864 | * 865 | * Usage examples: 866 | * 867 | * This is the default - case insensitive, no territories, no military zones 868 | * stateInput: { 869 | * caseSensitive: false, 870 | * includeTerritories: false, 871 | * includeMilitary: false 872 | * } 873 | * 874 | * Only allow capital letters, no territories, no military zones 875 | * stateInput: { 876 | * caseSensitive: false 877 | * } 878 | * 879 | * Case insensitive, include territories but not military zones 880 | * stateInput: { 881 | * includeTerritories: true 882 | * } 883 | * 884 | * Only allow capital letters, include territories and military zones 885 | * stateInput: { 886 | * caseSensitive: true, 887 | * includeTerritories: true, 888 | * includeMilitary: true 889 | * } 890 | * 891 | * 892 | * 893 | */ 894 | 895 | $.validator.addMethod("stateUS", function(value, element, options) { 896 | var isDefault = typeof options === "undefined", 897 | caseSensitive = ( isDefault || typeof options.caseSensitive === "undefined" ) ? false : options.caseSensitive, 898 | includeTerritories = ( isDefault || typeof options.includeTerritories === "undefined" ) ? false : options.includeTerritories, 899 | includeMilitary = ( isDefault || typeof options.includeMilitary === "undefined" ) ? false : options.includeMilitary, 900 | regex; 901 | 902 | if (!includeTerritories && !includeMilitary) { 903 | regex = "^(A[KLRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$"; 904 | } else if (includeTerritories && includeMilitary) { 905 | regex = "^(A[AEKLPRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOPST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])$"; 906 | } else if (includeTerritories) { 907 | regex = "^(A[KLRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOPST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])$"; 908 | } else { 909 | regex = "^(A[AEKLPRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$"; 910 | } 911 | 912 | regex = caseSensitive ? new RegExp(regex) : new RegExp(regex, "i"); 913 | return this.optional(element) || regex.test(value); 914 | }, 915 | "Please specify a valid state"); 916 | 917 | // TODO check if value starts with <, otherwise don't try stripping anything 918 | $.validator.addMethod("strippedminlength", function(value, element, param) { 919 | return $(value).text().length >= param; 920 | }, $.validator.format("Please enter at least {0} characters")); 921 | 922 | $.validator.addMethod("time", function(value, element) { 923 | return this.optional(element) || /^([01]\d|2[0-3]|[0-9])(:[0-5]\d){1,2}$/.test(value); 924 | }, "Please enter a valid time, between 00:00 and 23:59"); 925 | 926 | $.validator.addMethod("time12h", function(value, element) { 927 | return this.optional(element) || /^((0?[1-9]|1[012])(:[0-5]\d){1,2}(\ ?[AP]M))$/i.test(value); 928 | }, "Please enter a valid time in 12-hour am/pm format"); 929 | 930 | // same as url, but TLD is optional 931 | $.validator.addMethod("url2", function(value, element) { 932 | return this.optional(element) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)*(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value); 933 | }, $.validator.messages.url); 934 | 935 | /** 936 | * Return true, if the value is a valid vehicle identification number (VIN). 937 | * 938 | * Works with all kind of text inputs. 939 | * 940 | * @example 941 | * @desc Declares a required input element whose value must be a valid vehicle identification number. 942 | * 943 | * @name $.validator.methods.vinUS 944 | * @type Boolean 945 | * @cat Plugins/Validate/Methods 946 | */ 947 | $.validator.addMethod("vinUS", function(v) { 948 | if (v.length !== 17) { 949 | return false; 950 | } 951 | 952 | var LL = [ "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" ], 953 | VL = [ 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 7, 9, 2, 3, 4, 5, 6, 7, 8, 9 ], 954 | FL = [ 8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2 ], 955 | rs = 0, 956 | i, n, d, f, cd, cdv; 957 | 958 | for (i = 0; i < 17; i++) { 959 | f = FL[i]; 960 | d = v.slice(i, i + 1); 961 | if (i === 8) { 962 | cdv = d; 963 | } 964 | if (!isNaN(d)) { 965 | d *= f; 966 | } else { 967 | for (n = 0; n < LL.length; n++) { 968 | if (d.toUpperCase() === LL[n]) { 969 | d = VL[n]; 970 | d *= f; 971 | if (isNaN(cdv) && n === 8) { 972 | cdv = LL[n]; 973 | } 974 | break; 975 | } 976 | } 977 | } 978 | rs += d; 979 | } 980 | cd = rs % 11; 981 | if (cd === 10) { 982 | cd = "X"; 983 | } 984 | if (cd === cdv) { 985 | return true; 986 | } 987 | return false; 988 | }, "The specified vehicle identification number (VIN) is invalid."); 989 | 990 | $.validator.addMethod("zipcodeUS", function(value, element) { 991 | return this.optional(element) || /^\d{5}(-\d{4})?$/.test(value); 992 | }, "The specified US ZIP Code is invalid"); 993 | 994 | $.validator.addMethod("ziprange", function(value, element) { 995 | return this.optional(element) || /^90[2-5]\d\{2\}-\d{4}$/.test(value); 996 | }, "Your ZIP-code must be in the range 902xx-xxxx to 905xx-xxxx"); 997 | 998 | })); --------------------------------------------------------------------------------