From 2c734345e7904979c564cb82ee77c8691be4ba97 Mon Sep 17 00:00:00 2001 From: James South Date: Mon, 28 May 2012 16:23:27 +0100 Subject: [PATCH] First Commit Former-commit-id: 267292b5e198d1edec106c8b46222cdbcb9d8777 --- .gitattributes | 49 + .gitignore | 165 +++ README.md | 59 + src/ImageProcessor.Web/Caching/DiskCache.cs | 213 +++ .../Config/ImageCacheSection.cs | 76 + .../Config/ImageProcessingSection.cs | 312 ++++ .../Config/ImageProcessorConfig.cs | 255 ++++ .../Config/ImageSecuritySection.cs | 182 +++ .../Helpers/FileCompareLastwritetime.cs | 58 + src/ImageProcessor.Web/Helpers/RemoteFile.cs | 346 +++++ .../HttpModules/ImageProcessingModule.cs | 252 ++++ .../ImageFactoryExtensions.cs | 50 + .../ImageProcessor.Web.csproj | 80 + .../ImageProcessor.Web.vsdoc | 96 ++ .../Properties/AssemblyInfo.cs | 36 + .../Helpers/Extensions/EnumExtensions.cs | 40 + .../Helpers/Extensions/StringExtensions.cs | 116 ++ src/ImageProcessor/ImageFactory.cs | 498 +++++++ src/ImageProcessor/ImageProcessor.csproj | 86 ++ src/ImageProcessor/ImageProcessor.sln | 39 + src/ImageProcessor/ImageProcessor.sln.vsdoc | 7 + src/ImageProcessor/ImageProcessor.vsdoc | 103 ++ src/ImageProcessor/Imaging/ImageUtils.cs | 174 +++ src/ImageProcessor/Imaging/OctreeQuantizer.cs | 512 +++++++ .../Imaging/PaletteQuantizer.cs | 138 ++ src/ImageProcessor/Imaging/Quantizer.cs | 314 ++++ src/ImageProcessor/Imaging/ResponseType.cs | 62 + src/ImageProcessor/Processors/Alpha.cs | 175 +++ src/ImageProcessor/Processors/Crop.cs | 210 +++ src/ImageProcessor/Processors/Filter.cs | 292 ++++ src/ImageProcessor/Processors/Format.cs | 159 ++ .../Processors/IGraphicsProcessor.cs | 80 + src/ImageProcessor/Processors/Png8.cs | 147 ++ src/ImageProcessor/Processors/Quality.cs | 142 ++ src/ImageProcessor/Processors/Resize.cs | 235 +++ src/ImageProcessor/Processors/Vignette.cs | 200 +++ src/ImageProcessor/Properties/AssemblyInfo.cs | 36 + src/Test/Test.sln | 20 + src/Test/Test/Content/Site.css | 324 ++++ .../images/ui-bg_flat_0_aaaaaa_40x100.png | Bin 0 -> 180 bytes .../images/ui-bg_flat_75_ffffff_40x100.png | Bin 0 -> 178 bytes .../images/ui-bg_glass_55_fbf9ee_1x400.png | Bin 0 -> 120 bytes .../images/ui-bg_glass_65_ffffff_1x400.png | Bin 0 -> 105 bytes .../images/ui-bg_glass_75_dadada_1x400.png | Bin 0 -> 111 bytes .../images/ui-bg_glass_75_e6e6e6_1x400.png | Bin 0 -> 110 bytes .../images/ui-bg_glass_95_fef1ec_1x400.png | Bin 0 -> 119 bytes .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin 0 -> 101 bytes .../base/images/ui-icons_222222_256x240.png | Bin 0 -> 4369 bytes .../base/images/ui-icons_2e83ff_256x240.png | Bin 0 -> 4369 bytes .../base/images/ui-icons_454545_256x240.png | Bin 0 -> 4369 bytes .../base/images/ui-icons_888888_256x240.png | Bin 0 -> 4369 bytes .../base/images/ui-icons_cd0a0a_256x240.png | Bin 0 -> 4369 bytes .../themes/base/jquery.ui.accordion.css | 24 + .../Content/themes/base/jquery.ui.all.css | 16 + .../themes/base/jquery.ui.autocomplete.css | 62 + .../Content/themes/base/jquery.ui.base.css | 11 + .../Content/themes/base/jquery.ui.button.css | 43 + .../Content/themes/base/jquery.ui.core.css | 46 + .../themes/base/jquery.ui.datepicker.css | 73 + .../Content/themes/base/jquery.ui.dialog.css | 26 + .../themes/base/jquery.ui.progressbar.css | 16 + .../themes/base/jquery.ui.resizable.css | 25 + .../themes/base/jquery.ui.selectable.css | 15 + .../Content/themes/base/jquery.ui.slider.css | 29 + .../Content/themes/base/jquery.ui.tabs.css | 23 + .../Content/themes/base/jquery.ui.theme.css | 257 ++++ .../Test/Controllers/AccountController.cs | 193 +++ src/Test/Test/Controllers/HomeController.cs | 48 + src/Test/Test/Global.asax | 1 + src/Test/Test/Global.asax.cs | 40 + src/Test/Test/Images/1182076_e8c402e938_z.jpg | Bin 0 -> 51058 bytes ...6287131503_9b1f82e4f0_b.jpg.REMOVED.git-id | 1 + .../Images/Chrysanthemum.jpg.REMOVED.git-id | 1 + .../Images/Chrysanthemum.png.REMOVED.git-id | 1 + .../Test/Images/Desert.jpg.REMOVED.git-id | 1 + .../Test/Images/Hydrangeas.jpg.REMOVED.git-id | 1 + .../Test/Images/Jellyfish.jpg.REMOVED.git-id | 1 + src/Test/Test/Images/Koala.jpg.REMOVED.git-id | 1 + .../Test/Images/Lighthouse.jpg.REMOVED.git-id | 1 + ... - Wide Large - Rock 02.jpg.REMOVED.git-id | 1 + .../Test/Images/Penguins.jpg.REMOVED.git-id | 1 + .../Test/Images/Tulips.jpg.REMOVED.git-id | 1 + .../Test/Images/fid11246.jpg.REMOVED.git-id | 1 + .../Test/Images/fid9141.jpg.REMOVED.git-id | 1 + .../Images/war_horse_quad.jpg.REMOVED.git-id | 1 + src/Test/Test/Models/AccountModels.cs | 67 + src/Test/Test/Properties/AssemblyInfo.cs | 35 + .../MicrosoftAjax.debug.js.REMOVED.git-id | 1 + .../Scripts/MicrosoftAjax.js.REMOVED.git-id | 1 + .../Test/Scripts/MicrosoftMvcAjax.debug.js | 408 ++++++ src/Test/Test/Scripts/MicrosoftMvcAjax.js | 25 + .../Scripts/MicrosoftMvcValidation.debug.js | 883 +++++++++++ .../Test/Scripts/MicrosoftMvcValidation.js | 55 + .../jquery-1.5.1-vsdoc.js.REMOVED.git-id | 1 + .../Scripts/jquery-1.5.1.js.REMOVED.git-id | 1 + .../jquery-1.5.1.min.js.REMOVED.git-id | 1 + .../jquery-ui-1.8.11.js.REMOVED.git-id | 1 + .../jquery-ui-1.8.11.min.js.REMOVED.git-id | 1 + .../Test/Scripts/jquery.unobtrusive-ajax.js | 165 +++ .../Scripts/jquery.unobtrusive-ajax.min.js | 5 + .../Test/Scripts/jquery.validate-vsdoc.js | 1299 +++++++++++++++++ src/Test/Test/Scripts/jquery.validate.js | 1162 +++++++++++++++ src/Test/Test/Scripts/jquery.validate.min.js | 53 + .../Scripts/jquery.validate.unobtrusive.js | 319 ++++ .../jquery.validate.unobtrusive.min.js | 5 + src/Test/Test/Scripts/modernizr-1.7.js | 969 ++++++++++++ src/Test/Test/Scripts/modernizr-1.7.min.js | 10 + src/Test/Test/Test.csproj | 201 +++ src/Test/Test/Test.vsdoc | 7 + .../Test/Views/Account/ChangePassword.cshtml | 53 + .../Account/ChangePasswordSuccess.cshtml | 8 + src/Test/Test/Views/Account/LogOn.cshtml | 48 + src/Test/Test/Views/Account/Register.cshtml | 61 + src/Test/Test/Views/Home/About.cshtml | 14 + src/Test/Test/Views/Home/Index.cshtml | 10 + src/Test/Test/Views/Shared/Error.cshtml | 9 + src/Test/Test/Views/Shared/_Layout.cshtml | 33 + .../Test/Views/Shared/_LogOnPartial.cshtml | 7 + src/Test/Test/Views/Web.config | 58 + src/Test/Test/Views/_ViewStart.cshtml | 3 + src/Test/Test/Web.Debug.config | 30 + src/Test/Test/Web.Release.config | 31 + src/Test/Test/Web.config | 117 ++ src/Test/Test/packages.config | 9 + ...Framework.4.1.10331.0.nupkg.REMOVED.git-id | 1 + .../lib/EntityFramework.dll.REMOVED.git-id | 1 + .../lib/EntityFramework.xml.REMOVED.git-id | 1 + .../Content/Scripts/modernizr-1.7.js | 969 ++++++++++++ .../Content/Scripts/modernizr-1.7.min.js | 10 + .../Modernizr.1.7/Modernizr.1.7.nupkg | Bin 0 -> 20919 bytes .../Scripts/jquery-1.5.1.js.REMOVED.git-id | 1 + .../jquery-1.5.1.min.js.REMOVED.git-id | 1 + .../jQuery.1.5.1.nupkg.REMOVED.git-id | 1 + .../images/ui-bg_flat_0_aaaaaa_40x100.png | Bin 0 -> 180 bytes .../images/ui-bg_flat_75_ffffff_40x100.png | Bin 0 -> 178 bytes .../images/ui-bg_glass_55_fbf9ee_1x400.png | Bin 0 -> 120 bytes .../images/ui-bg_glass_65_ffffff_1x400.png | Bin 0 -> 105 bytes .../images/ui-bg_glass_75_dadada_1x400.png | Bin 0 -> 111 bytes .../images/ui-bg_glass_75_e6e6e6_1x400.png | Bin 0 -> 110 bytes .../images/ui-bg_glass_95_fef1ec_1x400.png | Bin 0 -> 119 bytes .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin 0 -> 101 bytes .../base/images/ui-icons_222222_256x240.png | Bin 0 -> 4369 bytes .../base/images/ui-icons_2e83ff_256x240.png | Bin 0 -> 4369 bytes .../base/images/ui-icons_454545_256x240.png | Bin 0 -> 4369 bytes .../base/images/ui-icons_888888_256x240.png | Bin 0 -> 4369 bytes .../base/images/ui-icons_cd0a0a_256x240.png | Bin 0 -> 4369 bytes .../themes/base/jquery.ui.accordion.css | 24 + .../Content/themes/base/jquery.ui.all.css | 16 + .../themes/base/jquery.ui.autocomplete.css | 62 + .../Content/themes/base/jquery.ui.base.css | 11 + .../Content/themes/base/jquery.ui.button.css | 43 + .../Content/themes/base/jquery.ui.core.css | 46 + .../themes/base/jquery.ui.datepicker.css | 73 + .../Content/themes/base/jquery.ui.dialog.css | 26 + .../themes/base/jquery.ui.progressbar.css | 16 + .../themes/base/jquery.ui.resizable.css | 25 + .../themes/base/jquery.ui.selectable.css | 15 + .../Content/themes/base/jquery.ui.slider.css | 29 + .../Content/themes/base/jquery.ui.tabs.css | 23 + .../Content/themes/base/jquery.ui.theme.css | 257 ++++ .../jquery-ui-1.8.11.js.REMOVED.git-id | 1 + .../jquery-ui-1.8.11.min.js.REMOVED.git-id | 1 + ...ry.UI.Combined.1.8.11.nupkg.REMOVED.git-id | 1 + .../Content/Scripts/jquery.validate-vsdoc.js | 1299 +++++++++++++++++ .../Content/Scripts/jquery.validate.js | 1162 +++++++++++++++ .../Content/Scripts/jquery.validate.min.js | 53 + .../jQuery.Validation.1.8.0.nupkg | Bin 0 -> 35004 bytes .../jquery-1.5.1-vsdoc.js.REMOVED.git-id | 1 + .../jQuery.vsdoc.1.5.1.nupkg.REMOVED.git-id | 1 + src/Test/packages/repositories.config | 4 + 170 files changed, 17640 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 README.md create mode 100644 src/ImageProcessor.Web/Caching/DiskCache.cs create mode 100644 src/ImageProcessor.Web/Config/ImageCacheSection.cs create mode 100644 src/ImageProcessor.Web/Config/ImageProcessingSection.cs create mode 100644 src/ImageProcessor.Web/Config/ImageProcessorConfig.cs create mode 100644 src/ImageProcessor.Web/Config/ImageSecuritySection.cs create mode 100644 src/ImageProcessor.Web/Helpers/FileCompareLastwritetime.cs create mode 100644 src/ImageProcessor.Web/Helpers/RemoteFile.cs create mode 100644 src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs create mode 100644 src/ImageProcessor.Web/ImageFactoryExtensions.cs create mode 100644 src/ImageProcessor.Web/ImageProcessor.Web.csproj create mode 100644 src/ImageProcessor.Web/ImageProcessor.Web.vsdoc create mode 100644 src/ImageProcessor.Web/Properties/AssemblyInfo.cs create mode 100644 src/ImageProcessor/Helpers/Extensions/EnumExtensions.cs create mode 100644 src/ImageProcessor/Helpers/Extensions/StringExtensions.cs create mode 100644 src/ImageProcessor/ImageFactory.cs create mode 100644 src/ImageProcessor/ImageProcessor.csproj create mode 100644 src/ImageProcessor/ImageProcessor.sln create mode 100644 src/ImageProcessor/ImageProcessor.sln.vsdoc create mode 100644 src/ImageProcessor/ImageProcessor.vsdoc create mode 100644 src/ImageProcessor/Imaging/ImageUtils.cs create mode 100644 src/ImageProcessor/Imaging/OctreeQuantizer.cs create mode 100644 src/ImageProcessor/Imaging/PaletteQuantizer.cs create mode 100644 src/ImageProcessor/Imaging/Quantizer.cs create mode 100644 src/ImageProcessor/Imaging/ResponseType.cs create mode 100644 src/ImageProcessor/Processors/Alpha.cs create mode 100644 src/ImageProcessor/Processors/Crop.cs create mode 100644 src/ImageProcessor/Processors/Filter.cs create mode 100644 src/ImageProcessor/Processors/Format.cs create mode 100644 src/ImageProcessor/Processors/IGraphicsProcessor.cs create mode 100644 src/ImageProcessor/Processors/Png8.cs create mode 100644 src/ImageProcessor/Processors/Quality.cs create mode 100644 src/ImageProcessor/Processors/Resize.cs create mode 100644 src/ImageProcessor/Processors/Vignette.cs create mode 100644 src/ImageProcessor/Properties/AssemblyInfo.cs create mode 100644 src/Test/Test.sln create mode 100644 src/Test/Test/Content/Site.css create mode 100644 src/Test/Test/Content/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png create mode 100644 src/Test/Test/Content/themes/base/images/ui-bg_flat_75_ffffff_40x100.png create mode 100644 src/Test/Test/Content/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png create mode 100644 src/Test/Test/Content/themes/base/images/ui-bg_glass_65_ffffff_1x400.png create mode 100644 src/Test/Test/Content/themes/base/images/ui-bg_glass_75_dadada_1x400.png create mode 100644 src/Test/Test/Content/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png create mode 100644 src/Test/Test/Content/themes/base/images/ui-bg_glass_95_fef1ec_1x400.png create mode 100644 src/Test/Test/Content/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png create mode 100644 src/Test/Test/Content/themes/base/images/ui-icons_222222_256x240.png create mode 100644 src/Test/Test/Content/themes/base/images/ui-icons_2e83ff_256x240.png create mode 100644 src/Test/Test/Content/themes/base/images/ui-icons_454545_256x240.png create mode 100644 src/Test/Test/Content/themes/base/images/ui-icons_888888_256x240.png create mode 100644 src/Test/Test/Content/themes/base/images/ui-icons_cd0a0a_256x240.png create mode 100644 src/Test/Test/Content/themes/base/jquery.ui.accordion.css create mode 100644 src/Test/Test/Content/themes/base/jquery.ui.all.css create mode 100644 src/Test/Test/Content/themes/base/jquery.ui.autocomplete.css create mode 100644 src/Test/Test/Content/themes/base/jquery.ui.base.css create mode 100644 src/Test/Test/Content/themes/base/jquery.ui.button.css create mode 100644 src/Test/Test/Content/themes/base/jquery.ui.core.css create mode 100644 src/Test/Test/Content/themes/base/jquery.ui.datepicker.css create mode 100644 src/Test/Test/Content/themes/base/jquery.ui.dialog.css create mode 100644 src/Test/Test/Content/themes/base/jquery.ui.progressbar.css create mode 100644 src/Test/Test/Content/themes/base/jquery.ui.resizable.css create mode 100644 src/Test/Test/Content/themes/base/jquery.ui.selectable.css create mode 100644 src/Test/Test/Content/themes/base/jquery.ui.slider.css create mode 100644 src/Test/Test/Content/themes/base/jquery.ui.tabs.css create mode 100644 src/Test/Test/Content/themes/base/jquery.ui.theme.css create mode 100644 src/Test/Test/Controllers/AccountController.cs create mode 100644 src/Test/Test/Controllers/HomeController.cs create mode 100644 src/Test/Test/Global.asax create mode 100644 src/Test/Test/Global.asax.cs create mode 100644 src/Test/Test/Images/1182076_e8c402e938_z.jpg create mode 100644 src/Test/Test/Images/6287131503_9b1f82e4f0_b.jpg.REMOVED.git-id create mode 100644 src/Test/Test/Images/Chrysanthemum.jpg.REMOVED.git-id create mode 100644 src/Test/Test/Images/Chrysanthemum.png.REMOVED.git-id create mode 100644 src/Test/Test/Images/Desert.jpg.REMOVED.git-id create mode 100644 src/Test/Test/Images/Hydrangeas.jpg.REMOVED.git-id create mode 100644 src/Test/Test/Images/Jellyfish.jpg.REMOVED.git-id create mode 100644 src/Test/Test/Images/Koala.jpg.REMOVED.git-id create mode 100644 src/Test/Test/Images/Lighthouse.jpg.REMOVED.git-id create mode 100644 src/Test/Test/Images/MSwanson - Wide Large - Rock 02.jpg.REMOVED.git-id create mode 100644 src/Test/Test/Images/Penguins.jpg.REMOVED.git-id create mode 100644 src/Test/Test/Images/Tulips.jpg.REMOVED.git-id create mode 100644 src/Test/Test/Images/fid11246.jpg.REMOVED.git-id create mode 100644 src/Test/Test/Images/fid9141.jpg.REMOVED.git-id create mode 100644 src/Test/Test/Images/war_horse_quad.jpg.REMOVED.git-id create mode 100644 src/Test/Test/Models/AccountModels.cs create mode 100644 src/Test/Test/Properties/AssemblyInfo.cs create mode 100644 src/Test/Test/Scripts/MicrosoftAjax.debug.js.REMOVED.git-id create mode 100644 src/Test/Test/Scripts/MicrosoftAjax.js.REMOVED.git-id create mode 100644 src/Test/Test/Scripts/MicrosoftMvcAjax.debug.js create mode 100644 src/Test/Test/Scripts/MicrosoftMvcAjax.js create mode 100644 src/Test/Test/Scripts/MicrosoftMvcValidation.debug.js create mode 100644 src/Test/Test/Scripts/MicrosoftMvcValidation.js create mode 100644 src/Test/Test/Scripts/jquery-1.5.1-vsdoc.js.REMOVED.git-id create mode 100644 src/Test/Test/Scripts/jquery-1.5.1.js.REMOVED.git-id create mode 100644 src/Test/Test/Scripts/jquery-1.5.1.min.js.REMOVED.git-id create mode 100644 src/Test/Test/Scripts/jquery-ui-1.8.11.js.REMOVED.git-id create mode 100644 src/Test/Test/Scripts/jquery-ui-1.8.11.min.js.REMOVED.git-id create mode 100644 src/Test/Test/Scripts/jquery.unobtrusive-ajax.js create mode 100644 src/Test/Test/Scripts/jquery.unobtrusive-ajax.min.js create mode 100644 src/Test/Test/Scripts/jquery.validate-vsdoc.js create mode 100644 src/Test/Test/Scripts/jquery.validate.js create mode 100644 src/Test/Test/Scripts/jquery.validate.min.js create mode 100644 src/Test/Test/Scripts/jquery.validate.unobtrusive.js create mode 100644 src/Test/Test/Scripts/jquery.validate.unobtrusive.min.js create mode 100644 src/Test/Test/Scripts/modernizr-1.7.js create mode 100644 src/Test/Test/Scripts/modernizr-1.7.min.js create mode 100644 src/Test/Test/Test.csproj create mode 100644 src/Test/Test/Test.vsdoc create mode 100644 src/Test/Test/Views/Account/ChangePassword.cshtml create mode 100644 src/Test/Test/Views/Account/ChangePasswordSuccess.cshtml create mode 100644 src/Test/Test/Views/Account/LogOn.cshtml create mode 100644 src/Test/Test/Views/Account/Register.cshtml create mode 100644 src/Test/Test/Views/Home/About.cshtml create mode 100644 src/Test/Test/Views/Home/Index.cshtml create mode 100644 src/Test/Test/Views/Shared/Error.cshtml create mode 100644 src/Test/Test/Views/Shared/_Layout.cshtml create mode 100644 src/Test/Test/Views/Shared/_LogOnPartial.cshtml create mode 100644 src/Test/Test/Views/Web.config create mode 100644 src/Test/Test/Views/_ViewStart.cshtml create mode 100644 src/Test/Test/Web.Debug.config create mode 100644 src/Test/Test/Web.Release.config create mode 100644 src/Test/Test/Web.config create mode 100644 src/Test/Test/packages.config create mode 100644 src/Test/packages/EntityFramework.4.1.10331.0/EntityFramework.4.1.10331.0.nupkg.REMOVED.git-id create mode 100644 src/Test/packages/EntityFramework.4.1.10331.0/lib/EntityFramework.dll.REMOVED.git-id create mode 100644 src/Test/packages/EntityFramework.4.1.10331.0/lib/EntityFramework.xml.REMOVED.git-id create mode 100644 src/Test/packages/Modernizr.1.7/Content/Scripts/modernizr-1.7.js create mode 100644 src/Test/packages/Modernizr.1.7/Content/Scripts/modernizr-1.7.min.js create mode 100644 src/Test/packages/Modernizr.1.7/Modernizr.1.7.nupkg create mode 100644 src/Test/packages/jQuery.1.5.1/Content/Scripts/jquery-1.5.1.js.REMOVED.git-id create mode 100644 src/Test/packages/jQuery.1.5.1/Content/Scripts/jquery-1.5.1.min.js.REMOVED.git-id create mode 100644 src/Test/packages/jQuery.1.5.1/jQuery.1.5.1.nupkg.REMOVED.git-id create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_flat_75_ffffff_40x100.png create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_glass_65_ffffff_1x400.png create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_glass_75_dadada_1x400.png create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_glass_95_fef1ec_1x400.png create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-icons_222222_256x240.png create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-icons_2e83ff_256x240.png create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-icons_454545_256x240.png create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-icons_888888_256x240.png create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-icons_cd0a0a_256x240.png create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.accordion.css create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.all.css create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.autocomplete.css create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.base.css create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.button.css create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.core.css create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.datepicker.css create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.dialog.css create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.progressbar.css create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.resizable.css create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.selectable.css create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.slider.css create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.tabs.css create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.theme.css create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Scripts/jquery-ui-1.8.11.js.REMOVED.git-id create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Scripts/jquery-ui-1.8.11.min.js.REMOVED.git-id create mode 100644 src/Test/packages/jQuery.UI.Combined.1.8.11/jQuery.UI.Combined.1.8.11.nupkg.REMOVED.git-id create mode 100644 src/Test/packages/jQuery.Validation.1.8.0/Content/Scripts/jquery.validate-vsdoc.js create mode 100644 src/Test/packages/jQuery.Validation.1.8.0/Content/Scripts/jquery.validate.js create mode 100644 src/Test/packages/jQuery.Validation.1.8.0/Content/Scripts/jquery.validate.min.js create mode 100644 src/Test/packages/jQuery.Validation.1.8.0/jQuery.Validation.1.8.0.nupkg create mode 100644 src/Test/packages/jQuery.vsdoc.1.5.1/Content/Scripts/jquery-1.5.1-vsdoc.js.REMOVED.git-id create mode 100644 src/Test/packages/jQuery.vsdoc.1.5.1/jQuery.vsdoc.1.5.1.nupkg.REMOVED.git-id create mode 100644 src/Test/packages/repositories.config diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..a664be3a8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,49 @@ +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain + +*.jpg binary +*.png binary +*.gif binary + +*.cs text=auto diff=csharp +*.vb text=auto +*.c text=auto +*.cpp text=auto +*.cxx text=auto +*.h text=auto +*.hxx text=auto +*.py text=auto +*.rb text=auto +*.java text=auto +*.html text=auto +*.htm text=auto +*.css text=auto +*.scss text=auto +*.sass text=auto +*.less text=auto +*.js text=auto +*.lisp text=auto +*.clj text=auto +*.sql text=auto +*.php text=auto +*.lua text=auto +*.m text=auto +*.asm text=auto +*.erl text=auto +*.fs text=auto +*.fsx text=auto +*.hs text=auto + +*.csproj text=auto merge=union +*.vbproj text=auto merge=union +*.fsproj text=auto merge=union +*.dbproj text=auto merge=union +*.sln text=auto eol=crlf merge=union diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..aa8811c67 --- /dev/null +++ b/.gitignore @@ -0,0 +1,165 @@ + +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/** +tmp/** +tmp/**/* +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +**/[Dd]ebug/ +**/[Rr]elease/ +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.vspscc +.builds +**/*.dotCover + +## TODO: If you have NuGet Package Restore enabled, uncomment this +#**/packages/ + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf + +# Visual Studio profiler +*.psess +*.vsp + +# ReSharper is a .NET coding add-in +_ReSharper* + +# Installshield output folder +[Ee]xpress + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish + +# Others +[Bb]in +[Oo]bj +sql +TestResults +*.Cache +ClientBin +stylecop.* +~$* +*.dbmdl +Generated_Code #added for RIA/Silverlight projects + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML + + + +############ +## Windows +############ + +# Windows image file caches +Thumbs.db + +# Folder config file +Desktop.ini + + +############# +## Python +############# + +*.py[co] + +# Packages +*.egg +*.egg-info +dist +build +eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg + +# Mac crap +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 000000000..2c3ade838 --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +ImageProcessor +=============== + +ImageProcessor is a library for on the fly processing of image files using Asp.Net + +The library architecture is highly extensible and allows for easy extension. + +Core plugins at present include: + + - Resize + - Crop + - Quality (The quality to set the output for jpeg files) + - Filter (Image filters including sepia, greyscale, blackwhite, lomograph) + - Vignette + - Format (Sets the output format) + - Alpha (Sets opacity) + +The library consists of two binaries: ImageProcessor.dll and ImageProcessor.Web.dll. + +ImageProcessor.dll contains all the core functionality that allows for image manipulation via the `ImageFactory` class. This has a fluent API which allows you to easily chain methods to deliver the desired output. + +e.g. + + // Read a file and resize it. + var photoBytes = File.ReadAllBytes(file); + var before = DateTime.Now; + var quality = 90; + var format = ImageFormat.Jpeg; + var thumbnailSize = 150; + + byte[] resized; + + using (var inStream = new MemoryStream(photoBytes)) + { + using (var outStream = new MemoryStream()) + { + using (ImageFactory imageFactory = new ImageFactory()) + { + // Load, resize and save an image. + imageFactory.Load(inStream).Format(format).Quality(quality).Resize(thumbnailSize, 0).Save(outStream); + } + + resized = outStream.ToArray(); + } + } + +ImageProcessor.Web.dll contains a HttpModule which captures internal and external requests automagically processing them based on values captured through querystring parameters. + +Using the HttpModule requires no code writing at all. Just reference the binaries and add the relevant sections to the web.config + +Image requests suffixed with QueryString parameters will then be processed and cached to the server allowing for easy and efficient parsing of following requests. + +e.g. + + your resized image + +Will resize your image to 200px wide whilst keeping the correct aspect ratio. + + diff --git a/src/ImageProcessor.Web/Caching/DiskCache.cs b/src/ImageProcessor.Web/Caching/DiskCache.cs new file mode 100644 index 000000000..4ce6021fb --- /dev/null +++ b/src/ImageProcessor.Web/Caching/DiskCache.cs @@ -0,0 +1,213 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Web.Caching +{ + #region Using + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Threading; + using System.Threading.Tasks; + using System.Web; + using System.Web.Hosting; + using ImageProcessor.Helpers.Extensions; + using ImageProcessor.Web.Config; + using ImageProcessor.Web.Helpers; + #endregion + + /// + /// Encapsulates methods to handle disk caching of images. + /// + internal sealed class DiskCache + { + #region Fields + /// + /// The maximum number or time a new file should be cached before checking the + /// cache controller and running any clearing mechanisms. + /// + /// + /// NTFS file systems can handle up to 8000 files in one directory. The Cache controller will clear out any + /// time we hit 6000 so if we tell the handler to run at every 1000 times an image is added to the cache we + /// should have a 1000 file buffer. + /// + internal const int MaxRunsBeforeCacheClear = 1000; + + /// + /// The maximum number of days to cache files on the system for. + /// + internal static readonly int MaxFileCachedDuration = ImageProcessorConfig.Instance.MaxCacheDays; + + /// + /// The object to lock against. + /// + private static readonly object SyncRoot = new object(); + + /// + /// The default paths for Cached folders on the server. + /// + private static readonly string CachePath = ImageProcessorConfig.Instance.VirtualCachePath; + + /// + /// The maximum number of files allowed in the directory. + /// + /// + /// NTFS Folder can handle up to 8000 files in a directory. + /// This buffer will help us to ensure that we rarely hit anywhere near that limit. + /// + private const int MaxFilesCount = 6000; + #endregion + + #region Methods + /// + /// Gets the full transformed cached path for the image. + /// + /// The original image path. + /// The original image name. + /// The full cached path for the image. + internal static string GetCachePath(string imagePath, string imageName) + { + string virtualCachePath = CachePath; + string absoluteCachePath = HostingEnvironment.MapPath(virtualCachePath); + string cachedPath = string.Empty; + + if (absoluteCachePath != null) + { + DirectoryInfo di = new DirectoryInfo(absoluteCachePath); + + if (!di.Exists) + { + // Create the directory. + Directory.CreateDirectory(absoluteCachePath); + } + + string cachedFileName = string.Format("{0}{1}", imagePath.ToMD5Fingerprint(), imageName.Substring(imageName.LastIndexOf(".", StringComparison.Ordinal))); + cachedPath = Path.Combine(absoluteCachePath, cachedFileName); + } + + return cachedPath; + } + + /// + /// Converts an absolute file path + /// + /// The absolute path to convert. + /// The from the current context. + /// The virtual path to the file. + internal static string GetVirtualPath(string absolutePath, HttpRequest request) + { + string applicationPath = request.PhysicalApplicationPath; + string virtualDir = request.ApplicationPath; + virtualDir = virtualDir == "/" ? virtualDir : (virtualDir + "/"); + if (applicationPath != null) + { + return absolutePath.Replace(applicationPath, virtualDir).Replace(@"\", "/"); + } + + throw new InvalidOperationException("We can only map an absolute back to a relative path if the application path is available."); + } + + /// + /// Purges any files from the filesystem cache in a background thread. + /// + internal static void PurgeCachedFolders() + { + ThreadStart threadStart = PurgeFolders; + + Thread thread = new Thread(threadStart) + { + IsBackground = true + }; + + thread.Start(); + } + + /// + /// Returns a value indicating whether the original file has been updated. + /// + /// The original image path. + /// The cached image path. + /// + /// True if the the original file has been updated; otherwise, false. + /// + internal static bool IsUpdatedFile(string imagePath, string cachedImagePath) + { + if (File.Exists(imagePath) && File.Exists(cachedImagePath)) + { + FileInfo imageFileInfo = new FileInfo(imagePath); + FileInfo cachedImageFileInfo = new FileInfo(cachedImagePath); + + return !new FileCompareLastwritetime().Equals(imageFileInfo, cachedImageFileInfo); + } + + return true; + } + + /// + /// Sets the LastWriteTime of the cached file to match the original file. + /// + /// The original image path. + /// The cached image path. + internal static void SetCachedLastWriteTime(string imagePath, string cachedImagePath) + { + if (File.Exists(imagePath) && File.Exists(cachedImagePath)) + { + lock (SyncRoot) + { + DateTime dateTime = File.GetLastWriteTime(imagePath); + File.SetLastWriteTime(cachedImagePath, dateTime); + } + } + } + + /// + /// Purges any files from the filesystem cache in the given folders. + /// + private static void PurgeFolders() + { + string folder = HostingEnvironment.MapPath(CachePath); + + if (folder != null) + { + DirectoryInfo directoryInfo = new DirectoryInfo(folder); + + if (directoryInfo.Exists) + { + // Get all the files in the cache ordered by LastAccessTime - oldest first. + List fileInfos = directoryInfo.EnumerateFiles("*", SearchOption.AllDirectories) + .OrderBy(x => x.LastAccessTime).ToList(); + + int counter = fileInfos.Count; + + Parallel.ForEach( + fileInfos, + fileInfo => + { + lock (SyncRoot) + { + try + { + // Delete the file if we are nearing our limit buffer. + if (counter >= MaxFilesCount || fileInfo.LastAccessTime < DateTime.Now.AddDays(-MaxFileCachedDuration)) + { + fileInfo.Delete(); + counter -= 1; + } + } + catch + { + // TODO: Sort out the try/catch. + throw; + } + } + }); + } + } + } + #endregion + } +} diff --git a/src/ImageProcessor.Web/Config/ImageCacheSection.cs b/src/ImageProcessor.Web/Config/ImageCacheSection.cs new file mode 100644 index 000000000..51a5831f4 --- /dev/null +++ b/src/ImageProcessor.Web/Config/ImageCacheSection.cs @@ -0,0 +1,76 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Web.Config +{ + #region Using + using System.Configuration; + using ImageProcessor.Helpers.Extensions; + #endregion + + /// + /// Represents an imagecache section within a configuration file. + /// + public class ImageCacheSection : ConfigurationSection + { + /// + /// Gets or sets the virtual path of the cache folder. + /// + /// The name of the cache folder. + [ConfigurationProperty("virtualPath", DefaultValue = "~/cache", IsRequired = true)] + [StringValidator(MinLength = 3, MaxLength = 200)] + public string VirtualPath + { + get + { + string virtualPath = (string)this["virtualPath"]; + + return virtualPath.IsValidVirtualPathName() ? virtualPath : "~/cache"; + } + + set + { + this["virtualPath"] = value; + } + } + + /// + /// Gets or sets the maximum number of days to store an image in the cache. + /// + /// The maximum number of days to store an image in the cache. + /// Defaults to 7 if not set. Maximum of 28. + [ConfigurationProperty("maxDays", DefaultValue = "7", IsRequired = false)] + [IntegerValidator(ExcludeRange = false, MaxValue = 28, MinValue = 0)] + public int MaxDays + { + get + { + return (int)this["maxDays"]; + } + + set + { + this["maxDays"] = value; + } + } + + /// + /// Retrieves the cache configuration section from the current application configuration. + /// + /// The cache configuration section from the current application configuration. + public static ImageCacheSection GetConfiguration() + { + ImageCacheSection imageCacheSection = ConfigurationManager.GetSection("imageProcessor/cache") as ImageCacheSection; + + if (imageCacheSection != null) + { + return imageCacheSection; + } + + return new ImageCacheSection(); + } + } +} diff --git a/src/ImageProcessor.Web/Config/ImageProcessingSection.cs b/src/ImageProcessor.Web/Config/ImageProcessingSection.cs new file mode 100644 index 000000000..9751e3ddf --- /dev/null +++ b/src/ImageProcessor.Web/Config/ImageProcessingSection.cs @@ -0,0 +1,312 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Web.Config +{ + #region Using + using System.Configuration; + using System.Linq; + #endregion + + /// + /// Represents an imageprocessing section within a configuration file. + /// Nested syntax adapted from http://tneustaedter.blogspot.co.uk/2011/09/how-to-create-one-or-more-nested.html + /// + public class ImageProcessingSection : ConfigurationSection + { + #region Properties + /// + /// Gets the . + /// + /// + /// The . + /// + [ConfigurationProperty("plugins", IsRequired = true)] + public PluginElementCollection Plugins + { + get + { + return this["plugins"] as PluginElementCollection; + } + } + #endregion + + #region Methods + /// + /// Retrieves the processing configuration section from the current application configuration. + /// + /// The processing configuration section from the current application configuration. + public static ImageProcessingSection GetConfiguration() + { + ImageProcessingSection imageProcessingSection = + ConfigurationManager.GetSection("imageProcessor/processing") as ImageProcessingSection; + + if (imageProcessingSection != null) + { + return imageProcessingSection; + } + + return new ImageProcessingSection(); + } + #endregion + + /// + /// Represents a PluginElement configuration element within the configuration. + /// + public class PluginElement : ConfigurationElement + { + /// + /// Gets or sets the name of the plugin file. + /// + /// The name of the plugin. + [ConfigurationProperty("name", DefaultValue = "", IsRequired = true)] + public string Name + { + get { return (string)this["name"]; } + + set { this["name"] = value; } + } + + /// + /// Gets the . + /// + /// + /// The . + /// + [ConfigurationProperty("settings", IsRequired = true)] + public SettingElementCollection Settings + { + get + { + return this["settings"] as SettingElementCollection; + } + } + } + + /// + /// Represents a PluginElementCollection collection configuration element within the configuration. + /// + public class PluginElementCollection : ConfigurationElementCollection + { + /// + /// Gets the type of the . + /// + /// + /// The of this collection. + /// + public override ConfigurationElementCollectionType CollectionType + { + get { return ConfigurationElementCollectionType.BasicMap; } + } + + /// + /// Gets the name used to identify this collection of elements in the configuration file when overridden in a derived class. + /// + /// + /// The name of the collection; otherwise, an empty string. The default is an empty string. + /// + protected override string ElementName + { + get { return "plugin"; } + } + + /// + /// Gets or sets the + /// at the specified index within the collection. + /// + /// The index at which to get the specified object. + /// + /// The the + /// at the specified index within the collection. + /// + public PluginElement this[int index] + { + get + { + return (PluginElement)BaseGet(index); + } + + set + { + if (BaseGet(index) != null) + { + BaseRemoveAt(index); + } + + BaseAdd(index, value); + } + } + + /// + /// Creates a new PluginConfig configuration element. + /// + /// + /// A new PluginConfig configuration element. + /// + protected override ConfigurationElement CreateNewElement() + { + return new PluginElement(); + } + + /// + /// Gets the element key for a specified PluginElement configuration element. + /// + /// + /// The ConfigurationElement + /// to return the key for. + /// + /// The element key for a specified PluginElement configuration element. + protected override object GetElementKey(ConfigurationElement element) + { + return ((PluginElement)element).Name; + } + } + + /// + /// Represents a SettingElement configuration element within the configuration. + /// + public class SettingElement : ConfigurationElement + { + /// + /// Gets or sets the key of the plugin setting. + /// + /// The key of the plugin setting. + [ConfigurationProperty("key", IsRequired = true, IsKey = true)] + public string Key + { + get + { + return this["key"] as string; + } + + set + { + this["key"] = value; + } + } + + /// + /// Gets or sets the value of the plugin setting. + /// + /// The value of the plugin setting. + [ConfigurationProperty("value", IsRequired = true)] + public string Value + { + get + { + return (string)this["value"]; + } + + set + { + this["value"] = value; + } + } + } + + /// + /// Represents a SettingElementCollection collection configuration element within the configuration. + /// + public class SettingElementCollection : ConfigurationElementCollection + { + /// + /// Gets the type of the . + /// + /// + /// The of this collection. + /// + public override ConfigurationElementCollectionType CollectionType + { + get { return ConfigurationElementCollectionType.BasicMap; } + } + + /// + /// Gets the name used to identify this collection of elements in the configuration file when overridden in a derived class. + /// + /// + /// The name of the collection; otherwise, an empty string. The default is an empty string. + /// + protected override string ElementName + { + get { return "setting"; } + } + + /// + /// Gets or sets the + /// at the specified index within the collection. + /// + /// The index at which to get the specified object. + /// + /// The the + /// at the specified index within the collection. + /// + public SettingElement this[int index] + { + get + { + return (SettingElement)BaseGet(index); + } + + set + { + if (BaseGet(index) != null) + { + BaseRemoveAt(index); + } + + BaseAdd(index, value); + } + } + + /// + /// Returns the setting element with the specified key. + /// + /// knkn knk + /// jn jnj + public new SettingElement this[string key] + { + get { return (SettingElement)BaseGet(key); } + } + + /// + /// Returns a value indicating whether the settings collection contains the + /// given object. + /// + /// The key to identify the setting. + /// True if the collection contains the key; otherwise false. + public bool ContainsKey(string key) + { + object[] keys = BaseGetAllKeys(); + + return keys.Any(obj => (string)obj == key); + } + + /// + /// Gets the element key for a specified PluginElement configuration element. + /// + /// + /// The ConfigurationElement + /// to return the key for. + /// + /// The element key for a specified PluginElement configuration element. + protected override object GetElementKey(ConfigurationElement element) + { + return ((SettingElement)element).Key; + } + + /// + /// Creates a new SettingElement configuration element. + /// + /// + /// A new SettingElement configuration element. + /// + protected override ConfigurationElement CreateNewElement() + { + return new SettingElement(); + } + } + } +} diff --git a/src/ImageProcessor.Web/Config/ImageProcessorConfig.cs b/src/ImageProcessor.Web/Config/ImageProcessorConfig.cs new file mode 100644 index 000000000..a47ae8de5 --- /dev/null +++ b/src/ImageProcessor.Web/Config/ImageProcessorConfig.cs @@ -0,0 +1,255 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Web.Config +{ + #region Using + using System; + using System.Collections.Generic; + using System.Linq; + using ImageProcessor.Processors; + #endregion + + /// + /// Encapsulates methods to allow the retrieval of imageprocessor settings. + /// http://csharpindepth.com/Articles/General/Singleton.aspx + /// + public class ImageProcessorConfig + { + #region Fields + /// + /// A new instance Initializes a new instance of the class. + /// intitialized lazily. + /// + private static readonly Lazy Lazy = + new Lazy(() => new ImageProcessorConfig()); + + /// + /// A collection of the elements + /// for available plugins. + /// + private static readonly Dictionary> PluginSettings = + new Dictionary>(); + + /// + /// The processing configuration section from the current application configuration. + /// + private static ImageProcessingSection imageProcessingSection; + + /// + /// The cache configuration section from the current application configuration. + /// + private static ImageCacheSection imageCacheSection; + + /// + /// The security configuration section from the current application configuration. + /// + private static ImageSecuritySection imageSecuritySection; + #endregion + + #region Constructors + /// + /// Prevents a default instance of the class from being created. + /// + private ImageProcessorConfig() + { + this.LoadGraphicsProcessors(); + } + #endregion + + #region Properties + /// + /// Gets the current instance of the class. + /// + public static ImageProcessorConfig Instance + { + get + { + return Lazy.Value; + } + } + + /// + /// Gets the list of available GraphicsProcessors. + /// + public List GraphicsProcessors { get; private set; } + + #region Caching + /// + /// Gets the maximum number of days to store images in the cache. + /// + public int MaxCacheDays + { + get + { + return GetImageCacheSection().MaxDays; + } + } + + /// + /// Gets or the virtual path of the cache folder. + /// + /// The virtual path of the cache folder. + public string VirtualCachePath + { + get + { + return GetImageCacheSection().VirtualPath; + } + } + #endregion + + #region Security + /// + /// Gets a list of whitelisted urls that images can be downloaded from. + /// + public Uri[] RemoteFileWhiteList + { + get + { + return GetImageSecuritySection().WhiteList.Cast().Select(x => x.Url).ToArray(); + } + } + + /// + /// Gets a value indicating whether the current application is allowed to download remote files. + /// + public bool AllowRemoteDownloads + { + get + { + return GetImageSecuritySection().AllowRemoteDownloads; + } + } + + /// + /// Gets the maximum length to wait in milliseconds before throwing an error requesting a remote file. + /// + public int Timeout + { + get + { + return GetImageSecuritySection().Timeout; + } + } + + /// + /// Gets the maximum allowable size in bytes of e remote file to process. + /// + public int MaxBytes + { + get + { + return GetImageSecuritySection().MaxBytes; + } + } + + /// + /// Gets the remote prefix for external files for the application. + /// + public string RemotePrefix + { + get + { + return GetImageSecuritySection().RemotePrefix; + } + } + #endregion + #endregion + + #region Methods + /// + /// Returns the for the given plugin. + /// + /// + /// The name of the plugin to get the settings for. + /// + /// + /// The for the given plugin. + /// + public Dictionary GetPluginSettings(string name) + { + if (!PluginSettings.ContainsKey(name)) + { + var pluginElement = + GetImageProcessingSection().Plugins + .Cast() + .FirstOrDefault(x => x.Name == name); + + Dictionary settings; + + if (pluginElement != null) + { + settings = pluginElement.Settings + .Cast() + .ToDictionary(setting => setting.Key, setting => setting.Value); + } + else + { + settings = new Dictionary(); + } + + PluginSettings.Add(name, settings); + return settings; + } + + return PluginSettings[name]; + } + + /// + /// Retrieves the processing configuration section from the current application configuration. + /// + /// The processing configuration section from the current application configuration. + private static ImageProcessingSection GetImageProcessingSection() + { + return imageProcessingSection ?? (imageProcessingSection = ImageProcessingSection.GetConfiguration()); + } + + /// + /// Retrieves the caching configuration section from the current application configuration. + /// + /// The caching configuration section from the current application configuration. + private static ImageCacheSection GetImageCacheSection() + { + return imageCacheSection ?? (imageCacheSection = ImageCacheSection.GetConfiguration()); + } + + /// + /// Retrieves the security configuration section from the current application configuration. + /// + /// The security configuration section from the current application configuration. + private static ImageSecuritySection GetImageSecuritySection() + { + return imageSecuritySection ?? (imageSecuritySection = ImageSecuritySection.GetConfiguration()); + } + + /// + /// Gets the list of available GraphicsProcessors. + /// + private void LoadGraphicsProcessors() + { + if (this.GraphicsProcessors == null) + { + // Build a list of native IGraphicsProcessor instances. + Type type = typeof(IGraphicsProcessor); + IEnumerable types = + AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes()).Where( + p => type.IsAssignableFrom(p) && p.IsClass && !p.IsAbstract).ToList(); + + // Create them and add. + this.GraphicsProcessors = + types.Select(x => (Activator.CreateInstance(x) as IGraphicsProcessor)).ToList(); + + // Add the available settings. + foreach (IGraphicsProcessor processor in this.GraphicsProcessors) + { + processor.Settings = this.GetPluginSettings(processor.Name); + } + } + } + #endregion + } +} diff --git a/src/ImageProcessor.Web/Config/ImageSecuritySection.cs b/src/ImageProcessor.Web/Config/ImageSecuritySection.cs new file mode 100644 index 000000000..0e17cc7a5 --- /dev/null +++ b/src/ImageProcessor.Web/Config/ImageSecuritySection.cs @@ -0,0 +1,182 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Web.Config +{ + #region Using + using System; + using System.Configuration; + #endregion + + /// + /// Represents an imagecache section within a configuration file. + /// + public class ImageSecuritySection : ConfigurationSection + { + #region Properties + /// + /// Gets or sets a value indicating whether the current application is allowed download remote files. + /// + /// if the current application is allowed download remote files; otherwise, . + [ConfigurationProperty("allowRemoteDownloads", DefaultValue = false, IsRequired = true)] + public bool AllowRemoteDownloads + { + get { return (bool)this["allowRemoteDownloads"]; } + set { this["allowRemoteDownloads"] = value; } + } + + /// + /// Gets or sets the maximum allowed remote file timeout in milliseconds for the application. + /// + /// The maximum number of days to store an image in the cache. + /// Defaults to 30000 (30 seconds) if not set. + [ConfigurationProperty("timeout", DefaultValue = "300000", IsRequired = true)] + public int Timeout + { + get + { + return (int)this["timeout"]; + } + + set + { + this["timeout"] = value; + } + } + + /// + /// Gets or sets the maximum allowed remote file size in bytes for the application. + /// + /// The maximum number of days to store an image in the cache. + /// Defaults to 524288 (512kb) if not set. + [ConfigurationProperty("maxBytes", DefaultValue = "524288", IsRequired = true)] + public int MaxBytes + { + get + { + return (int)this["maxBytes"]; + } + + set + { + this["maxBytes"] = value; + } + } + + /// + /// Gets or sets the prefix for remote files for the application. + /// + /// The prefix for remote files for the application. + [ConfigurationProperty("remotePrefix", DefaultValue = "", IsRequired = true)] + public string RemotePrefix + { + get { return (string)this["remotePrefix"]; } + + set { this["remotePrefix"] = value; } + } + + /// + /// Gets the + /// + /// The + [ConfigurationProperty("whiteList", IsRequired = true)] + public WhiteListElementCollection WhiteList + { + get + { + object o = this["whiteList"]; + return o as WhiteListElementCollection; + } + } + #endregion + + #region Methods + /// + /// Retrieves the security configuration section from the current application configuration. + /// + /// The cache configuration section from the current application configuration. + public static ImageSecuritySection GetConfiguration() + { + ImageSecuritySection imageSecuritySection = ConfigurationManager.GetSection("imageProcessor/security") as ImageSecuritySection; + + if (imageSecuritySection != null) + { + return imageSecuritySection; + } + + return new ImageSecuritySection(); + } + #endregion + + /// + /// Represents a whitelist collection configuration element within the configuration. + /// + public class WhiteListElementCollection : ConfigurationElementCollection + { + /// + /// Gets or sets the whitelist item at the given index. + /// + /// The index of the whitelist item to get. + /// The whitelist item at the given index. + public SafeURL this[int index] + { + get + { + return this.BaseGet(index) as SafeURL; + } + + set + { + if (this.BaseGet(index) != null) + { + this.BaseRemoveAt(index); + } + + this.BaseAdd(index, value); + } + } + + /// + /// Creates a new SafeURL configuration element. + /// + /// + /// A new SafeURL configuration element. + /// + protected override ConfigurationElement CreateNewElement() + { + return new SafeURL(); + } + + /// + /// Gets the element key for a specified whitelist configuration element. + /// + /// The ConfigurationElement to return the key for. + /// The element key for a specified whitelist configuration element. + protected override object GetElementKey(ConfigurationElement element) + { + return ((SafeURL)element).Url; + } + } + + /// + /// Represents a whitelist configuration element within the configuration. + /// + public class SafeURL : ConfigurationElement + { + /// + /// Gets or sets the url of the whitelisted file. + /// + /// The url of the whitelisted file. + [ConfigurationProperty("url", DefaultValue = "", IsRequired = true)] + public Uri Url + { + get { return (Uri)this["url"]; } + + set { this["url"] = value; } + } + } + } +} diff --git a/src/ImageProcessor.Web/Helpers/FileCompareLastwritetime.cs b/src/ImageProcessor.Web/Helpers/FileCompareLastwritetime.cs new file mode 100644 index 000000000..3fc315b5e --- /dev/null +++ b/src/ImageProcessor.Web/Helpers/FileCompareLastwritetime.cs @@ -0,0 +1,58 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Web.Helpers +{ + #region Using + using System; + using System.Collections.Generic; + #endregion + + /// + /// Encapsulates methods to support the comparison of objects for equality. + /// + public class FileCompareLastwritetime : IEqualityComparer + { + /// + /// Converts the value of the current object to its equivalent + /// nearest minute representation. + /// + /// An instance of . + /// + /// A value of the current object to its equivalent + /// nearest minute representation. + /// + public static DateTime ToMinute(DateTime value) + { + return new DateTime(value.Year, value.Month, value.Day, value.Hour, value.Minute, 0, value.Kind); + } + + /// + /// Determines whether the specified instances of object are equal. + /// + /// + /// The first object to compare. + /// + /// + /// The second object to compare. + /// + /// true if the specified objects are equal; otherwise, false. + public bool Equals(System.IO.FileInfo f1, System.IO.FileInfo f2) + { + return ToMinute(f1.LastWriteTime) == ToMinute(f2.LastWriteTime); + } + + /// + /// Returns a hash code for the specified . + /// + /// The FileInfo to return the hashcode for. + /// A hash code for the specified . + public int GetHashCode(System.IO.FileInfo fi) + { + return ToMinute(fi.LastWriteTime).GetHashCode(); + } + } +} diff --git a/src/ImageProcessor.Web/Helpers/RemoteFile.cs b/src/ImageProcessor.Web/Helpers/RemoteFile.cs new file mode 100644 index 000000000..af637b7ee --- /dev/null +++ b/src/ImageProcessor.Web/Helpers/RemoteFile.cs @@ -0,0 +1,346 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Web.Helpers +{ + #region Using + using System; + using System.Diagnostics.Contracts; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Net; + using System.Security; + using System.Text; + using ImageProcessor.Web.Config; + #endregion + + /// + /// Encapsulates methods used to download files from a website address. + /// + /// + /// + /// The purpose of this class is so there's one core way of downloading remote files with urls that are from + /// outside users. There's various areas in application where an attacker could supply an external url to the server + /// and tie up resources. + /// + /// For example, the ImageProcessingModule accepts off-server addresses as a path. An attacker could, for instance, pass the url + /// to a file that's a few gigs in size, causing the server to get out-of-memory exceptions or some other errors. An attacker + /// could also use this same method to use one application instance to hammer another site by, again, passing an off-server + /// address of the victims site to the ImageProcessingModule. + /// This class will not throw an exception if the Uri supplied points to a resource local to the running application instance. + /// + /// There shouldn't be any security issues there, as the internal WebRequest instance is still calling it remotely. + /// Any local files that shouldn't be accessed by this won't be allowed by the remote call. + /// + /// Adapted from BlogEngine.Net + /// + internal sealed class RemoteFile + { + #region Fields + /// + /// The white-list of urls from which to download remote files. + /// + private static readonly Uri[] RemoteFileWhiteList = ImageProcessorConfig.Instance.RemoteFileWhiteList; + + /// + /// The length of time, in milliseconds, that a remote file download attempt can last before timing out. + /// + private static readonly int TimeoutMilliseconds = ImageProcessorConfig.Instance.Timeout; + + /// + /// The maximum size, in bytes, that a remote file download attempt can download. + /// + private static readonly int MaxBytes = ImageProcessorConfig.Instance.MaxBytes; + + /// + /// Whether to allow remote downloads. + /// + private static readonly bool AllowRemoteDownloads = ImageProcessorConfig.Instance.AllowRemoteDownloads; + + /// + /// Whether this RemoteFile instance is ignoring remote download rules set in the current application + /// instance. + /// + private readonly bool ignoreRemoteDownloadSettings; + + /// + /// The Uri of the remote file being downloaded. + /// + private readonly Uri url; + + /// + /// The maximum allowable download size in bytes. + /// + private readonly int maxDownloadSize; + + /// + /// The length of time, in milliseconds, that a remote file download attempt can last before timing out. + /// + private int timeoutLength; + + /// + /// The WebResponse object used internally for this RemoteFile instance. + /// + private WebRequest webRequest; + #endregion + + #region Constructors + /// + /// Initializes a new instance of the RemoteFile class. + /// + /// The url of the file to be downloaded. + /// + /// If set to , then RemoteFile should ignore the current the applications instance's remote download settings; otherwise,. + /// + internal RemoteFile(Uri filePath, bool ignoreRemoteDownloadSettings) + { + Contract.Requires(filePath != null); + + this.url = filePath; + this.ignoreRemoteDownloadSettings = ignoreRemoteDownloadSettings; + this.timeoutLength = TimeoutMilliseconds; + this.maxDownloadSize = MaxBytes; + } + #endregion + + #region Properties + /// + /// Gets a value indicating whether this RemoteFile instance is ignoring remote download rules set in the + /// current application instance. + /// + /// This should only be set to true if the supplied url is a verified resource. Use at your own risk. + /// + /// + /// + /// if this RemoteFile instance is ignoring remote download rules set in the current + /// application instance; otherwise, . + /// + public bool IgnoreRemoteDownloadSettings + { + get + { + return this.ignoreRemoteDownloadSettings; + } + } + + /// + /// Gets the Uri of the remote file being downloaded. + /// + public Uri Uri + { + get + { + return this.url; + } + } + + /// + /// Gets or sets the length of time, in milliseconds, that a remote file download attempt can + /// last before timing out. + /// + /// + /// This value can only be set if the instance is supposed to ignore the remote download settings set + /// in the current application instance. + /// + /// + /// Set this value to 0 if there should be no timeout. + /// + /// + /// + public int TimeoutLength + { + get + { + return this.IgnoreRemoteDownloadSettings ? this.timeoutLength : TimeoutMilliseconds; + } + + set + { + if (!this.IgnoreRemoteDownloadSettings) + { + throw new SecurityException("Timeout length can not be adjusted on remote files that are abiding by remote download rules"); + } + + if (value < 0) + { + throw new ArgumentOutOfRangeException("TimeoutLength"); + } + + this.timeoutLength = value; + } + } + + /// + /// Gets or sets the maximum download size, in bytes, that a remote file download attempt can be. + /// + /// + /// This value can only be set if the instance is supposed to ignore the remote download settings set + /// in the current application instance. + /// + /// + /// Set this value to 0 if there should be no timeout. + /// + /// + /// + public int MaxDownloadSize + { + get + { + return this.IgnoreRemoteDownloadSettings ? this.maxDownloadSize : MaxBytes; + } + + set + { + if (!this.IgnoreRemoteDownloadSettings) + { + throw new SecurityException("Max Download Size can not be adjusted on remote files that are abiding by remote download rules"); + } + + if (value < 0) + { + throw new ArgumentOutOfRangeException("MaxDownloadSize"); + } + + this.timeoutLength = value; + } + } + #endregion + + #region Methods + #region Public + /// + /// Returns the WebResponse used to download this file. + /// + /// + /// This method is meant for outside users who need specific access to the WebResponse this class + /// generates. They're responsible for disposing of it. + /// + /// + /// + /// The WebResponse used to download this file. + public WebResponse GetWebResponse() + { + WebResponse response = this.GetWebRequest().GetResponse(); + + long contentLength = response.ContentLength; + + // WebResponse.ContentLength doesn't always know the value, it returns -1 in this case. + if (contentLength == -1) + { + // Response headers may still have the Content-Length inside of it. + string headerContentLength = response.Headers["Content-Length"]; + + if (!string.IsNullOrWhiteSpace(headerContentLength)) + { + contentLength = long.Parse(headerContentLength, CultureInfo.InvariantCulture); + } + } + + // We don't need to check the url here since any external urls are available only from the web.config. + if ((this.MaxDownloadSize > 0) && (contentLength > this.MaxDownloadSize)) + { + response.Close(); + throw new SecurityException("An attempt to download a remote file has been halted because the file is larger than allowed."); + } + + return response; + } + + /// + /// Returns the remote file as a String. + /// + /// This returns the resulting stream as a string as passed through a StreamReader. + /// + /// + /// The remote file as a String. + public string GetFileAsString() + { + using (WebResponse response = this.GetWebResponse()) + { + Stream responseStream = response.GetResponseStream(); + + if (responseStream != null) + { + // Pipe the stream to a stream reader with the required encoding format. + using (StreamReader reader = new StreamReader(responseStream, Encoding.UTF8)) + { + return reader.ReadToEnd(); + } + } + + return string.Empty; + } + } + #endregion + + #region Private + /// + /// Performs a check to see whether the application is able to download remote files. + /// + private void CheckCanDownload() + { + if (!this.IgnoreRemoteDownloadSettings && !AllowRemoteDownloads) + { + throw new SecurityException("application is not configured to allow remote file downloads."); + } + } + + /// + /// Creates the WebRequest object used internally for this RemoteFile instance. + /// + /// + /// + /// The WebRequest should not be passed outside of this instance, as it will allow tampering. Anyone + /// that needs more fine control over the downloading process should probably be using the WebRequest + /// class on its own. + /// + /// + private WebRequest GetWebRequest() + { + // Check downloads are allowed. + this.CheckCanDownload(); + + // Check the url is from a whitelisted location. + this.CheckSafeUrlLocation(); + + if (this.webRequest == null) + { + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.Uri); + request.Headers["Accept-Encoding"] = "gzip"; + request.Headers["Accept-Language"] = "en-us"; + request.Credentials = CredentialCache.DefaultNetworkCredentials; + request.AutomaticDecompression = DecompressionMethods.GZip; + + if (this.TimeoutLength > 0) + { + request.Timeout = this.TimeoutLength; + } + + this.webRequest = request; + } + + return this.webRequest; + } + + /// + /// Returns a value indicating whether the current url is in a list of safe download locations. + /// + private void CheckSafeUrlLocation() + { + bool validUrl = RemoteFileWhiteList.Any(item => item.Host.ToUpperInvariant().Equals(this.url.Host.ToUpperInvariant())); + + if (!validUrl) + { + throw new SecurityException("application is not configured to allow remote file downloads from this domain."); + } + } + #endregion + #endregion + } +} + + diff --git a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs new file mode 100644 index 000000000..335df1cb5 --- /dev/null +++ b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs @@ -0,0 +1,252 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Web.HttpModules +{ + #region Using + using System; + using System.IO; + using System.Net; + using System.Web; + using System.Web.Hosting; + using ImageProcessor.Helpers.Extensions; + using ImageProcessor.Imaging; + using ImageProcessor.Web.Caching; + using ImageProcessor.Web.Config; + using ImageProcessor.Web.Helpers; + #endregion + + /// + /// TODO: Update summary. + /// + public class ImageProcessingModule : IHttpModule + { + #region Fields + /// + /// The value to prefix any remote image requests with to ensure they get captured. + /// + private static readonly string RemotePrefix = ImageProcessorConfig.Instance.RemotePrefix; + + /// + /// The key for storing the response type of the current image. + /// + private const string CachedResponseTypeKey = "CACHED_IMAGE_RESPONSE_TYPE"; + + /// + /// Whether this is the first run of the handler. + /// + private static bool isFirstRun = true; + + /// + /// A counter for keeping track of how many images have been added to the cache. + /// + private static int cachedImageCounter; + #endregion + + #region IHttpModule Members + /// + /// Initializes a module and prepares it to handle requests. + /// + /// An that provides access to the methods, properties, and events common to all application objects within an ASP.NET application + public void Init(HttpApplication context) + { + context.BeginRequest += this.ContextBeginRequest; + context.PreSendRequestHeaders += this.ContextPreSendRequestHeaders; + } + + /// + /// Disposes of the resources (other than memory) used by the module that implements . + /// + public void Dispose() + { + // Nothing to dispose. + } + #endregion + + /// + /// Occurs as the first event in the HTTP pipeline chain of execution when ASP.NET responds to a request. + /// + /// The source of the event. + /// An EventArgs that contains the event data. + private void ContextBeginRequest(object sender, EventArgs e) + { + HttpContext context = ((HttpApplication)sender).Context; + + // Is this a remote file. + bool isRemote = context.Request.Path.Equals(RemotePrefix, StringComparison.OrdinalIgnoreCase); + string path; + string queryString = string.Empty; + + if (isRemote) + { + // We need to split the querystring to get the actual values we want. + string[] paths = HttpUtility.UrlDecode(context.Request.QueryString.ToString()).Split('?'); + + path = paths[0]; + + if (paths.Length > 1) + { + queryString = paths[1]; + } + } + else + { + path = HostingEnvironment.MapPath(context.Request.Path); + queryString = context.Request.QueryString.ToString(); + } + + if (ImageUtils.IsValidImageExtension(path) && !string.IsNullOrWhiteSpace(queryString)) + { + string fullPath = string.Format("{0}?{1}", path, queryString); + string imageName = Path.GetFileName(path); + string cachedPath = DiskCache.GetCachePath(fullPath, imageName); + + if (path != null && this.FileExists(path, isRemote)) + { + bool exists = File.Exists(cachedPath); + bool updated = DiskCache.IsUpdatedFile(path, cachedPath); + + if ((exists == false) || (!isRemote && updated)) + { + // Check to see if this is the first run and if so run the cache controller. + if (isFirstRun) + { + // Trim the cache. + DiskCache.PurgeCachedFolders(); + + // Disable the controller. + isFirstRun = false; + } + + // ImageFactory.Instance.Load(fullPath).AutoProcess().Save(cachedPath); + using (ImageFactory imageFactory = new ImageFactory()) + { + if (isRemote) + { + Uri uri = new Uri(path); + RemoteFile remoteFile = new RemoteFile(uri, false); + + using (MemoryStream memoryStream = new MemoryStream()) + { + using (Stream responseStream = remoteFile.GetWebResponse().GetResponseStream()) + { + if (responseStream != null) + { + responseStream.CopyTo(memoryStream); + + imageFactory.Load(memoryStream) + .AddQueryString(queryString) + .Format(ImageUtils.GetImageFormat(imageName)) + .AutoProcess().Save(cachedPath); + } + } + } + } + else + { + imageFactory.Load(fullPath).AutoProcess().Save(cachedPath); + } + } + + // Add 1 to the counter + cachedImageCounter += 1; + + // Ensure that the LastWriteTime property of the source and cached file match. + DiskCache.SetCachedLastWriteTime(path, cachedPath); + + // If the number of cached imaged hits the maximum allowed for this session then we clear + // the cache again and reset the counter + if (cachedImageCounter >= DiskCache.MaxRunsBeforeCacheClear) + { + DiskCache.PurgeCachedFolders(); + cachedImageCounter = 0; + } + } + + context.Items[CachedResponseTypeKey] = ImageUtils.GetResponseType(imageName).ToDescription(); + + // The cached file is valid so just rewrite the path. + context.RewritePath(DiskCache.GetVirtualPath(cachedPath, context.Request), false); + } + } + } + + /// + /// Occurs just before ASP.NET send Httpheaders to the client. + /// + /// The source of the event. + /// An EventArgs that contains the event data. + private void ContextPreSendRequestHeaders(object sender, EventArgs e) + { + HttpContext context = ((HttpApplication)sender).Context; + + object responseTypeObject = context.Items[CachedResponseTypeKey]; + + if (responseTypeObject != null) + { + string responseType = (string)responseTypeObject; + + this.SetHeaders(context, responseType); + + context.Items[CachedResponseTypeKey] = null; + } + } + + #region Private + /// + /// returns a value indicating whether a file exists. + /// + /// The path to the file to check. + /// Whether the file is remote. + /// True if the file exists, otherwise false. + /// If the file is remote the method will always return true. + private bool FileExists(string path, bool remote) + { + return remote || File.Exists(path); + } + + /// + /// This will make the browser and server keep the output + /// in its cache and thereby improve performance. + /// See http://en.wikipedia.org/wiki/HTTP_ETag + /// + /// + /// the HttpContext object that provides + /// references to the intrinsic server objects + /// + /// The HTTP MIME type to to send. + private void SetHeaders(HttpContext context, string responseType) + { + HttpResponse response = context.Response; + + response.ContentType = responseType; + + HttpCachePolicy cache = response.Cache; + + cache.VaryByHeaders["Accept-Encoding"] = true; + + int maxDays = DiskCache.MaxFileCachedDuration; + + cache.SetExpires(DateTime.Now.ToUniversalTime().AddDays(maxDays)); + cache.SetMaxAge(new TimeSpan(maxDays, 0, 0, 0)); + cache.SetRevalidation(HttpCacheRevalidation.AllCaches); + + string incomingEtag = context.Request.Headers["If-None-Match"]; + + cache.SetCacheability(HttpCacheability.Public); + + if (incomingEtag == null) + { + return; + } + + response.Clear(); + response.StatusCode = (int)HttpStatusCode.NotModified; + response.SuppressContent = true; + } + #endregion + } +} diff --git a/src/ImageProcessor.Web/ImageFactoryExtensions.cs b/src/ImageProcessor.Web/ImageFactoryExtensions.cs new file mode 100644 index 000000000..cf2eb7d49 --- /dev/null +++ b/src/ImageProcessor.Web/ImageFactoryExtensions.cs @@ -0,0 +1,50 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Web +{ + #region Using + using System.Collections.Generic; + using System.Linq; + using ImageProcessor.Processors; + using ImageProcessor.Web.Config; + #endregion + + /// + /// Extends the ImageFactory class to provide a fluent api. + /// + public static class ImageFactoryExtensions + { + /// + /// Auto processes image files based on any querystring parameters added to the image path. + /// + /// + /// The current instance of the class + /// that this method extends. + /// + /// + /// The current instance of the class. + /// + public static ImageFactory AutoProcess(this ImageFactory factory) + { + if (factory.ShouldProcess) + { + // Get a list of all graphics processors that have parsed and matched the querystring. + List list = + ImageProcessorConfig.Instance.GraphicsProcessors.Where(x => x.MatchRegexIndex(factory.QueryString) != int.MaxValue).OrderBy( + y => y.SortOrder).ToList(); + + // Loop through and process the image. + foreach (IGraphicsProcessor graphicsProcessor in list) + { + factory.Image = graphicsProcessor.ProcessImage(factory); + } + } + + return factory; + } + } +} diff --git a/src/ImageProcessor.Web/ImageProcessor.Web.csproj b/src/ImageProcessor.Web/ImageProcessor.Web.csproj new file mode 100644 index 000000000..6f5589cf3 --- /dev/null +++ b/src/ImageProcessor.Web/ImageProcessor.Web.csproj @@ -0,0 +1,80 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43} + Library + Properties + ImageProcessor.Web + ImageProcessor.Web + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\All\ + DEBUG;TRACE + full + AnyCPU + prompt + + + + + + + + + + + + + + + + + + + + + + + + + + + + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} + ImageProcessor + + + + + + \ No newline at end of file diff --git a/src/ImageProcessor.Web/ImageProcessor.Web.vsdoc b/src/ImageProcessor.Web/ImageProcessor.Web.vsdoc new file mode 100644 index 000000000..26a18eb4c --- /dev/null +++ b/src/ImageProcessor.Web/ImageProcessor.Web.vsdoc @@ -0,0 +1,96 @@ + + + + default + + +]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + normal + yes + ImageProcessor.Web Reference + imageprocessorweb_reference + vsdocman_escaped_]_]_> + + + + placeholder + no + + d85a6fde0cd5454f9dc418dda28f5422 + + + + + + +]]> + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ImageProcessor.Web/Properties/AssemblyInfo.cs b/src/ImageProcessor.Web/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..0f5e66028 --- /dev/null +++ b/src/ImageProcessor.Web/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ImageProcessor.Web")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ImageProcessor.Web")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("cef6713b-4088-488a-ad2c-6f94aff082d5")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/ImageProcessor/Helpers/Extensions/EnumExtensions.cs b/src/ImageProcessor/Helpers/Extensions/EnumExtensions.cs new file mode 100644 index 000000000..f9a771c70 --- /dev/null +++ b/src/ImageProcessor/Helpers/Extensions/EnumExtensions.cs @@ -0,0 +1,40 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Helpers.Extensions +{ + #region Using + using System; + using System.ComponentModel; + using System.Diagnostics.Contracts; + #endregion + + /// + /// Encapsulates a series of time saving extension methods to Enums. + /// + public static class EnumExtensions + { + #region Methods + /// + /// Extends the Enum type to return the description attribute for the given type. + /// Useful for when the type to match in the data source contains spaces. + /// + /// The given Enum that this method extends. + /// A string containing the Enum's description attribute. + public static string ToDescription(this Enum expression) + { + Contract.Requires(expression != null); + + DescriptionAttribute[] descriptionAttribute = + (DescriptionAttribute[]) + expression.GetType().GetField(expression.ToString()) + .GetCustomAttributes(typeof(DescriptionAttribute), false); + + return descriptionAttribute.Length > 0 ? descriptionAttribute[0].Description : expression.ToString(); + } + #endregion + } +} diff --git a/src/ImageProcessor/Helpers/Extensions/StringExtensions.cs b/src/ImageProcessor/Helpers/Extensions/StringExtensions.cs new file mode 100644 index 000000000..32976d937 --- /dev/null +++ b/src/ImageProcessor/Helpers/Extensions/StringExtensions.cs @@ -0,0 +1,116 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Helpers.Extensions +{ + #region Using + using System.Diagnostics.Contracts; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Security.Cryptography; + using System.Text; + using System.Text.RegularExpressions; + #endregion + + /// + /// Encapsulates a series of time saving extension methods to Strings. + /// + public static class StringExtensions + { + #region Cryptography + /// + /// Creates an MD5 fingerprint of the String. + /// + /// The String instance that this method extends. + /// An MD5 fingerprint of the String. + public static string ToMD5Fingerprint(this string expression) + { + Contract.Requires(!string.IsNullOrWhiteSpace(expression)); + + byte[] bytes = Encoding.Unicode.GetBytes(expression.ToCharArray()); + + using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider()) + { + byte[] hash = md5.ComputeHash(bytes); + + // Concatenate the hash bytes into one long String. + return hash.Aggregate( + new StringBuilder(32), + (sb, b) => sb.Append(b.ToString("X2", CultureInfo.InvariantCulture))) + .ToString(); + } + } + #endregion + + #region Numbers + /// + /// Creates an array of integers scraped from the String. + /// + /// The String instance that this method extends. + /// An array of integers scraped from the String. + public static int[] ToIntegerArray(this string expression) + { + Contract.Requires(!string.IsNullOrWhiteSpace(expression)); + + Regex regex = new Regex(@"\d+", RegexOptions.Compiled); + + MatchCollection matchCollection = regex.Matches(expression); + + // Get the collections. + int count = matchCollection.Count; + int[] matches = new int[count]; + + // Loop and parse the int values. + for (int i = 0; i < count; i++) + { + matches[i] = int.Parse(matchCollection[i].Value); + } + + return matches; + } + #endregion + + #region Files and Paths + /// + /// Checks the string to see whether the value is a valid virtual path name. + /// + /// The String instance that this method extends. + /// True if the given string is a valid virtual path name + public static bool IsValidVirtualPathName(this string expression) + { + Contract.Requires(!string.IsNullOrWhiteSpace(expression)); + + // Check the start of the string. + if (expression.StartsWith("~/")) + { + // Trim the first two characters and test the path. + expression = expression.Substring(2); + return expression.IsValidPathName(); + } + + return false; + } + + /// + /// Checks the string to see whether the value is a valid path name. + /// http://stackoverflow.com/questions/62771/how-check-if-given-string-is-legal-allowed-file-name-under-windows/ + /// + /// The String instance that this method extends. + /// True if the given string is a valid path name + public static bool IsValidPathName(this string expression) + { + Contract.Requires(!string.IsNullOrWhiteSpace(expression)); + + // Create a regex of invalid characters and test it. + string invalidPathNameChars = new string(Path.GetInvalidFileNameChars()); + Regex regFixPathName = new Regex("[" + Regex.Escape(invalidPathNameChars) + "]"); + + return !regFixPathName.IsMatch(expression); + } + #endregion + } +} diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs new file mode 100644 index 000000000..718bd7e15 --- /dev/null +++ b/src/ImageProcessor/ImageFactory.cs @@ -0,0 +1,498 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor +{ + #region Using + using System; + using System.Collections.Generic; + using System.Drawing; + using System.Drawing.Imaging; + using System.IO; + using System.Linq; + using ImageProcessor.Imaging; + using ImageProcessor.Processors; + + #endregion + + /// + /// Encapsulates methods for processing image files. + /// http://csharpindepth.com/Articles/General/Singleton.aspx + /// + public class ImageFactory : IDisposable + { + #region Fields + /// + /// The default quality for jpeg files. + /// + private const int DefaultJpegQuality = 90; + + /// + /// A value indicating whether this instance of the given entity has been disposed. + /// + /// if this instance has been disposed; otherwise, . + /// + /// If the entity is disposed, it must not be disposed a second + /// time. The isDisposed field is set the first time the entity + /// is disposed. If the isDisposed field is true, then the Dispose() + /// method will not dispose again. This help not to prolong the entity's + /// life in the Garbage Collector. + /// + private bool isDisposed; + #endregion + + #region Destructors + /// + /// Finalizes an instance of the ImageFactory class. + /// + /// + /// Use C# destructor syntax for finalization code. + /// This destructor will run only if the Dispose method + /// does not get called. + /// It gives your base class the opportunity to finalize. + /// Do not provide destructors in types derived from this class. + /// + ~ImageFactory() + { + // Do not re-create Dispose clean-up code here. + // Calling Dispose(false) is optimal in terms of + // readability and maintainability. + this.Dispose(false); + } + + #endregion + + #region Properties + /// + /// Gets or sets the local image for manipulation. + /// + public Image Image { get; set; } + + /// + /// Gets the path to the local image for manipulation. + /// + public string ImagePath { get; private set; } + + /// + /// Gets the querystring params for web image manipulation. + /// + public string QueryString { get; private set; } + + /// + /// Gets a value indicating whether the image factory should process the file. + /// + public bool ShouldProcess { get; private set; } + + /// + /// Gets or sets the quality of output for jpeg images as a percentile. + /// + internal int JpegQuality { get; set; } + + /// + /// Gets or sets the file format of the image. + /// + internal ImageFormat ImageFormat { get; set; } + #endregion + + #region Methods + + /// + /// Loads the image to process. Always call this method first. + /// + /// + /// The containing the image information. + /// + /// + /// The current instance of the class. + /// + public ImageFactory Load(MemoryStream memoryStream) + { + // Set our image as the memorystream value. + this.Image = Image.FromStream(memoryStream); + + // Store the stream in the image Tag property so we can dispose of it later. + this.Image.Tag = memoryStream; + + // Set the other properties. + this.JpegQuality = DefaultJpegQuality; + this.ImageFormat = ImageFormat.Jpeg; + this.ShouldProcess = true; + + return this; + } + + /// + /// Loads the image to process. Always call this method first. + /// + /// The absolute path to the image to load. + /// + /// The current instance of the class. + /// + public ImageFactory Load(string imagePath) + { + string[] paths = imagePath.Split('?'); + string path = paths[0]; + string query = string.Empty; + + if (paths.Length > 1) + { + query = paths[1]; + } + + string imageName = Path.GetFileName(path); + + if (File.Exists(path)) + { + this.ImagePath = path; + this.QueryString = query; + + // Open a filstream to prevent the need for lock. + using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read)) + { + MemoryStream memoryStream = new MemoryStream(); + + // Copy the stream. + fileStream.CopyTo(memoryStream); + + // Set the position to 0 afterwards. + fileStream.Position = memoryStream.Position = 0; + + // Set our image as the memorystream value. + this.Image = Image.FromStream(memoryStream); + + // Store the stream in the image Tag property so we can dispose of it later. + this.Image.Tag = memoryStream; + + // Set the other properties. + this.JpegQuality = DefaultJpegQuality; + this.ImageFormat = ImageUtils.GetImageFormat(imageName); + this.ShouldProcess = true; + } + } + + return this; + } + + #region Manipulation + + /// + /// Adds a querystring to the image factory to allow autoprocessing of remote files. + /// + /// The querystring parameter to process. + /// + /// The current instance of the class. + /// + public ImageFactory AddQueryString(string query) + { + if (this.ShouldProcess) + { + this.QueryString = query; + } + + return this; + } + + /// + /// Changes the opacity of the current image. + /// + /// The percentage by which to alter the images opacity. + /// + /// The current instance of the class. + /// + public ImageFactory Alpha(int percentage) + { + if (this.ShouldProcess) + { + var alpha = new Alpha { DynamicParameter = percentage }; + + this.Image = alpha.ProcessImage(this); + } + + return this; + } + + /// + /// Crops an image to the given coordinates. + /// + /// + /// The containing the coordinates to crop the image to. + /// + /// + /// The current instance of the class. + /// + public ImageFactory Crop(Rectangle rectangle) + { + if (this.ShouldProcess) + { + var crop = new Crop { DynamicParameter = rectangle }; + + this.Image = crop.ProcessImage(this); + } + + return this; + } + + /// + /// Applies a filter to an image. + /// + /// + /// The name of the filter to add to the image. + /// + /// + /// The current instance of the class. + /// + public ImageFactory Filter(string filterName) + { + if (this.ShouldProcess) + { + var filter = new Filter { DynamicParameter = filterName }; + + this.Image = filter.ProcessImage(this); + } + + return this; + } + + /// + /// Sets the output format of the image to the matching . + /// + /// The . to set the image to. + /// + /// The current instance of the class. + /// + public ImageFactory Format(ImageFormat imageFormat) + { + if (this.ShouldProcess) + { + this.ImageFormat = imageFormat; + } + + return this; + } + + /// + /// Applies a filter to an image. + /// + /// A value between 1 and 100 to set the quality to. + /// + /// The current instance of the class. + /// + public ImageFactory Quality(int percentage) + { + if (this.ShouldProcess) + { + this.JpegQuality = percentage; + } + + return this; + } + + /// + /// Resizes an image to the given dimensions. + /// + /// The width to set the image to. + /// The height to set the image to. + /// + /// The current instance of the class. + /// + public ImageFactory Resize(int width, int height) + { + if (this.ShouldProcess) + { + var resizeSettings = new Dictionary { { "MaxWidth", width.ToString("G") }, { "MaxHeight", height.ToString("G") } }; + + var resize = new Resize { DynamicParameter = new Size(width, height), Settings = resizeSettings }; + + this.Image = resize.ProcessImage(this); + } + + return this; + } + + /// + /// Adds a vignette image effect to the current image. + /// + /// + /// The current instance of the class. + /// + public ImageFactory Vignette() + { + if (this.ShouldProcess) + { + var vignette = new Vignette(); + + this.Image = vignette.ProcessImage(this); + } + + return this; + } + #endregion + + /// + /// Saves the current image to the specified file path. + /// + /// The path to save the image to. + public void Save(string filePath) + { + if (this.ShouldProcess) + { + // Fix the colour palette of gif images. + this.FixGifs(); + + if (this.ImageFormat == ImageFormat.Jpeg) + { + // Jpegs can be saved with different settings to include a quality setting for the JPEG compression. + // This improves output compression and quality. + using (EncoderParameters encoderParameters = ImageUtils.GetEncodingParameters(this.JpegQuality)) + { + ImageCodecInfo imageCodecInfo = + ImageCodecInfo.GetImageEncoders().FirstOrDefault( + ici => ici.MimeType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase)); + + this.Image.Save(filePath, imageCodecInfo, encoderParameters); + } + } + else + { + this.Image.Save(filePath, this.ImageFormat); + } + } + } + + /// + /// Saves the current image to the specified output stream. + /// + /// + /// The to save the image information to. + /// + public void Save(MemoryStream memoryStream) + { + if (this.ShouldProcess) + { + // Fix the colour palette of gif images. + this.FixGifs(); + + if (this.ImageFormat == ImageFormat.Jpeg) + { + // Jpegs can be saved with different settings to include a quality setting for the JPEG compression. + // This improves output compression and quality. + using (EncoderParameters encoderParameters = ImageUtils.GetEncodingParameters(this.JpegQuality)) + { + ImageCodecInfo imageCodecInfo = + ImageCodecInfo.GetImageEncoders().FirstOrDefault( + ici => ici.MimeType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase)); + + if (imageCodecInfo != null) + { + this.Image.Save(memoryStream, imageCodecInfo, encoderParameters); + } + } + } + else + { + this.Image.Save(memoryStream, this.ImageFormat); + } + } + } + + #region IDisposable Members + /// + /// Disposes the object and frees resources for the Garbage Collector. + /// + public void Dispose() + { + this.Dispose(true); + + // This object will be cleaned up by the Dispose method. + // Therefore, you should call GC.SupressFinalize to + // take this object off the finalization queue + // and prevent finalization code for this object + // from executing a second time. + GC.SuppressFinalize(this); + } + + /// + /// Disposes the object and frees resources for the Garbage Collector. + /// + /// If true, the object gets disposed. + protected virtual void Dispose(bool disposing) + { + if (this.isDisposed) + { + return; + } + + if (disposing) + { + // Dispose of any managed resources here. + if (this.Image != null) + { + // Dispose of the memorystream from Load and the image. + if (this.Image.Tag != null) + { + ((IDisposable)this.Image.Tag).Dispose(); + this.Image.Tag = null; + } + + this.Image.Dispose(); + this.Image = null; + } + } + + // Call the appropriate methods to clean up + // unmanaged resources here. + // Note disposing is done. + this.isDisposed = true; + } + #endregion + + /// + /// Saves the current image to the specified file path and resets any internal parameters. + /// + /// The path to save the image to. + private void SaveFile(string filePath) + { + // Fix the colour palette of gif images. + this.FixGifs(); + + if (this.ImageFormat == ImageFormat.Jpeg) + { + // Jpegs can be saved with different settings to include a quality setting for the JPEG compression. + // This improves output compression and quality. + using (EncoderParameters encoderParameters = ImageUtils.GetEncodingParameters(this.JpegQuality)) + { + ImageCodecInfo imageCodecInfo = ImageCodecInfo.GetImageEncoders() + .FirstOrDefault(ici => ici.MimeType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase)); + + if (imageCodecInfo != null) + { + this.Image.Save(filePath, imageCodecInfo, encoderParameters); + } + } + } + else + { + this.Image.Save(filePath, this.ImageFormat); + } + } + + /// + /// Uses the + /// to fix the colour palette of gif images. + /// + private void FixGifs() + { + // Fix the colour palette of gif images. + // TODO: Why does the palette not get fixed when resized to the same dimensions. + if (this.ImageFormat == ImageFormat.Gif) + { + OctreeQuantizer quantizer = new OctreeQuantizer(255, 8); + this.Image = quantizer.Quantize(this.Image); + } + } + #endregion + } +} diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj new file mode 100644 index 000000000..22ffe9fa3 --- /dev/null +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -0,0 +1,86 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} + Library + Properties + ImageProcessor + ImageProcessor + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\ImageProcessor.XML + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\ImageProcessor.XML + + + true + bin\All\ + DEBUG;TRACE + bin\Debug\ImageProcessor.XML + full + AnyCPU + prompt + false + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ImageProcessor/ImageProcessor.sln b/src/ImageProcessor/ImageProcessor.sln new file mode 100644 index 000000000..bdf26b14e --- /dev/null +++ b/src/ImageProcessor/ImageProcessor.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor", "ImageProcessor.csproj", "{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "..\Test\Test\Test.csproj", "{30327C08-7574-4D7E-AC95-6A58753C6855}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web", "..\ImageProcessor.Web\ImageProcessor.Web.csproj", "{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + All|Any CPU = All|Any CPU + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.ActiveCfg = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.Build.0 = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Any CPU.Build.0 = Release|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.ActiveCfg = All|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.Build.0 = All|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.Build.0 = Release|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.ActiveCfg = All|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.Build.0 = All|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/ImageProcessor/ImageProcessor.sln.vsdoc b/src/ImageProcessor/ImageProcessor.sln.vsdoc new file mode 100644 index 000000000..9ffff5e7f --- /dev/null +++ b/src/ImageProcessor/ImageProcessor.sln.vsdoc @@ -0,0 +1,7 @@ + + + + default + + + diff --git a/src/ImageProcessor/ImageProcessor.vsdoc b/src/ImageProcessor/ImageProcessor.vsdoc new file mode 100644 index 000000000..75458c7ac --- /dev/null +++ b/src/ImageProcessor/ImageProcessor.vsdoc @@ -0,0 +1,103 @@ + + + + default + + +]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + normal + yes + ImageProcessor Reference + imageprocessor_reference + vsdocman_escaped_]_]_> + + + + placeholder + no + + e3cba20ec62e422b8bb39e6be7ca2142 + + + + + + +]]> + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ImageProcessor/Imaging/ImageUtils.cs b/src/ImageProcessor/Imaging/ImageUtils.cs new file mode 100644 index 000000000..e5525e44c --- /dev/null +++ b/src/ImageProcessor/Imaging/ImageUtils.cs @@ -0,0 +1,174 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Imaging +{ + #region Using + using System; + using System.Drawing.Imaging; + using System.IO; + using System.Linq; + using System.Threading.Tasks; + #endregion + + /// + /// Encapsulates useful image utility methods. + /// + public static class ImageUtils + { + /// + /// Returns the correct response type based on the given file extension. + /// + /// The string containing the filename to check against. + /// The correct response type based on the given file extension. + public static ResponseType GetResponseType(string fileName) + { + string extension = Path.GetExtension(fileName); + if (extension != null) + { + string ext = extension.ToUpperInvariant(); + + switch (ext) + { + case ".PNG": + return ResponseType.Png; + case ".BMP": + return ResponseType.Bmp; + case ".GIF": + return ResponseType.Gif; + default: + // Should be a jpeg. + return ResponseType.Jpeg; + } + } + + // TODO: Should we call this on bad request? + return ResponseType.Jpeg; + } + + /// + /// Returns the correct image format based on the given file extension. + /// + /// The string containing the filename to check against. + /// The correct image format based on the given filename. + public static ImageFormat GetImageFormat(string fileName) + { + string extension = Path.GetExtension(fileName); + if (extension != null) + { + string ext = extension.ToUpperInvariant(); + + switch (ext) + { + case ".PNG": + return ImageFormat.Png; + case ".BMP": + return ImageFormat.Bmp; + case ".GIF": + return ImageFormat.Gif; + default: + // Should be a jpeg. + return ImageFormat.Jpeg; + } + } + // TODO: SHow custom exception?? + return null; + } + + /// + /// Returns the correct image format based on the given response type. + /// + /// + /// The to check against. + /// + /// The correct image format based on the given response type. + public static ImageFormat GetImageFormat(ResponseType responseType) + { + switch (responseType) + { + case ResponseType.Png: + return ImageFormat.Png; + case ResponseType.Bmp: + return ImageFormat.Bmp; + case ResponseType.Gif: + return ImageFormat.Gif; + default: + // Should be a jpeg. + return ImageFormat.Jpeg; + } + } + + /// + /// Returns the first ImageCodeInfo instance with the specified mime type. + /// + /// + /// A string that contains the codec's Multipurpose Internet Mail Extensions (MIME) type. + /// + /// + /// The first ImageCodeInfo instance with the specified mime type. + /// + public static ImageCodecInfo GetImageCodeInfo(string mimeType) + { + ImageCodecInfo[] info = ImageCodecInfo.GetImageEncoders(); + return info.FirstOrDefault(ici => ici.MimeType.Equals(mimeType, StringComparison.OrdinalIgnoreCase)); + } + + /// + /// Returns an instance of EncodingParameters for jpeg comression. + /// + /// The quality to return the image at. + /// The encodingParameters for jpeg comression. + public static EncoderParameters GetEncodingParameters(int quality) + { + EncoderParameters encoderParameters = null; + try + { + // Create a series of encoder parameters. + encoderParameters = new EncoderParameters(1); + + // Set the quality. + encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality); + } + catch + { + if (encoderParameters != null) + { + encoderParameters.Dispose(); + } + } + + return encoderParameters; + } + + /// + /// Checks a given string to check whether the value contains a valid image extension. + /// + /// The string containing the filename to check. + /// True the value contains a valid image extension, otherwise false. + public static bool IsValidImageExtension(string fileName) + { + bool isValid = false; + + if (!string.IsNullOrWhiteSpace(fileName)) + { + string[] fileExtensions = { ".BMP", ".JPG", ".PNG", ".GIF", ".JPEG" }; + + Parallel.ForEach( + fileExtensions, + (extension, loop) => + { + if (fileName.ToUpperInvariant().EndsWith(extension)) + { + isValid = true; + loop.Stop(); + } + }); + } + + return isValid; + } + } +} diff --git a/src/ImageProcessor/Imaging/OctreeQuantizer.cs b/src/ImageProcessor/Imaging/OctreeQuantizer.cs new file mode 100644 index 000000000..d9c9928a2 --- /dev/null +++ b/src/ImageProcessor/Imaging/OctreeQuantizer.cs @@ -0,0 +1,512 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Imaging +{ + #region Using + using System; + using System.Collections; + using System.Drawing; + using System.Drawing.Imaging; + #endregion + + /// + /// Encapsulates methods to calculate the colour palette if an image using an octree pattern. + /// + internal class OctreeQuantizer : Quantizer + { + #region Fields + /// + /// Stores the tree. + /// + private readonly Octree octree; + + /// + /// The maximum allowed color depth. + /// + private readonly int maxColors; + #endregion + + /// + /// Initializes a new instance of the OctreeQuantizer class. + /// + /// + /// The Octree quantizer is a two pass algorithm. The initial pass sets up the octree, + /// the second pass quantizes a colour based on the nodes in the tree + /// + /// The maximum number of colours to return, maximum 255. + /// The number of significant bits minimum 1, maximum 8. + public OctreeQuantizer(int maxColors, int maxColorBits) + : base(false) + { + if (maxColors > 255) + { + throw new ArgumentOutOfRangeException("maxColors", maxColors, "The number of colours should be less than 256"); + } + + if ((maxColorBits < 1) | (maxColorBits > 8)) + { + throw new ArgumentOutOfRangeException("maxColorBits", maxColorBits, "This should be between 1 and 8"); + } + + // Construct the octree + this.octree = new Octree(maxColorBits); + this.maxColors = maxColors; + } + + /// + /// Process the pixel in the first pass of the algorithm. + /// + /// The pixel to quantize + /// + /// This function need only be overridden if your quantize algorithm needs two passes, + /// such as an Octree quantizer. + /// + protected override void InitialQuantizePixel(Color32 pixel) + { + // Add the colour to the octree + this.octree.AddColor(pixel); + } + + /// + /// Override this to process the pixel in the second pass of the algorithm. + /// + /// The pixel to quantize + /// The quantized value. + protected override byte QuantizePixel(Color32 pixel) + { + // The colour at [this.maxColors] is set to transparent + byte paletteIndex; + + // Get the palette index if this non-transparent + if (pixel.Alpha > 0) + { + paletteIndex = (byte)this.octree.GetPaletteIndex(pixel); + } + else + { + paletteIndex = (byte)this.maxColors; + } + + return paletteIndex; + } + + /// + /// Retrieve the palette for the quantized image + /// + /// Any old palette, this is overwritten + /// The new colour palette + protected override ColorPalette GetPalette(ColorPalette original) + { + // First off convert the octree to this.maxColors colours + ArrayList palette = this.octree.Palletize(this.maxColors - 1); + + // Then convert the palette based on those colours + for (int index = 0; index < palette.Count; index++) + { + original.Entries[index] = (Color)palette[index]; + } + + // Add the transparent colour + original.Entries[this.maxColors] = Color.FromArgb(0, 0, 0, 0); + + return original; + } + + /// + /// Describes a tree data structure in which each internal node has exactly eight children. + /// + private class Octree + { + /// + /// Initializes a new instance of the Octree class. + /// + /// The maximum number of significant bits in the image + public Octree(int maxColorBits) + { + this._maxColorBits = maxColorBits; + this._leafCount = 0; + this._reducibleNodes = new OctreeNode[9]; + this._root = new OctreeNode(0, this._maxColorBits, this); + this._previousColor = 0; + this._previousNode = null; + } + + /// + /// Add a given colour value to the octree + /// + /// + /// The color value to add. + /// + public void AddColor(Color32 pixel) + { + // Check if this request is for the same colour as the last + if (this._previousColor == pixel.ARGB) + { + // If so, check if I have a previous node setup. This will only occur if the first colour in the image + // happens to be black, with an alpha component of zero. + if (null == this._previousNode) + { + this._previousColor = pixel.ARGB; + this._root.AddColor(pixel, this._maxColorBits, 0, this); + } + else + { + // Just update the previous node + this._previousNode.Increment(pixel); + } + } + else + { + this._previousColor = pixel.ARGB; + this._root.AddColor(pixel, this._maxColorBits, 0, this); + } + } + + /// + /// Reduce the depth of the tree + /// + public void Reduce() + { + // Find the deepest level containing at least one reducible node + int index = this._maxColorBits - 1; + while ((index > 0) && (this._reducibleNodes[index] == null)) + { + index--; + } + + // Reduce the node most recently added to the list at level 'index' + OctreeNode node = this._reducibleNodes[index]; + this._reducibleNodes[index] = node.NextReducible; + + // Decrement the leaf count after reducing the node + this._leafCount -= node.Reduce(); + + // And just in case I've reduced the last color to be added, and the next color to + // be added is the same, invalidate the previousNode... + this._previousNode = null; + } + + /// + /// Get or sets the number of leaves in the tree + /// + public int Leaves + { + get { return this._leafCount; } + set { this._leafCount = value; } + } + + /// + /// Return the array of reducible nodes + /// + protected OctreeNode[] ReducibleNodes + { + get { return this._reducibleNodes; } + } + + /// + /// Keep track of the previous node that was quantized + /// + /// The node last quantized + protected void TrackPrevious(OctreeNode node) + { + this._previousNode = node; + } + + /// + /// Convert the nodes in the octree to a palette with a maximum of colorCount colours + /// + /// The maximum number of colours + /// An array list with the palletized colours + public ArrayList Palletize(int colorCount) + { + while (this.Leaves > colorCount) + { + this.Reduce(); + } + + // Now palletize the nodes + ArrayList palette = new ArrayList(this.Leaves); + int paletteIndex = 0; + this._root.ConstructPalette(palette, ref paletteIndex); + + // And return the palette + return palette; + } + + /// + /// Get the palette index for the passed colour + /// + /// + /// + public int GetPaletteIndex(Color32 pixel) + { + return this._root.GetPaletteIndex(pixel, 0); + } + + /// + /// Mask used when getting the appropriate pixels for a given node + /// + private static int[] mask = new int[8] { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; + + /// + /// The root of the octree + /// + private OctreeNode _root; + + /// + /// Number of leaves in the tree + /// + private int _leafCount; + + /// + /// Array of reducible nodes + /// + private OctreeNode[] _reducibleNodes; + + /// + /// Maximum number of significant bits in the image + /// + private int _maxColorBits; + + /// + /// Store the last node quantized + /// + private OctreeNode _previousNode; + + /// + /// Cache the previous color quantized + /// + private int _previousColor; + + /// + /// Class which encapsulates each node in the tree + /// + protected class OctreeNode + { + /// + /// Construct the node + /// + /// The level in the tree = 0 - 7 + /// The number of significant color bits in the image + /// The tree to which this node belongs + public OctreeNode(int level, int colorBits, Octree octree) + { + // Construct the new node + this._leaf = (level == colorBits); + + this._red = _green = _blue = 0; + this._pixelCount = 0; + + // If a leaf, increment the leaf count + if (this._leaf) + { + octree.Leaves++; + this._nextReducible = null; + this._children = null; + } + else + { + // Otherwise add this to the reducible nodes + this._nextReducible = octree.ReducibleNodes[level]; + octree.ReducibleNodes[level] = this; + this._children = new OctreeNode[8]; + } + } + + /// + /// Add a color into the tree + /// + /// The color + /// The number of significant color bits + /// The level in the tree + /// The tree to which this node belongs + public void AddColor(Color32 pixel, int colorBits, int level, Octree octree) + { + // Update the color information if this is a leaf + if (this._leaf) + { + Increment(pixel); + // Setup the previous node + octree.TrackPrevious(this); + } + else + { + // Go to the next level down in the tree + int shift = 7 - level; + int index = ((pixel.Red & mask[level]) >> (shift - 2)) | + ((pixel.Green & mask[level]) >> (shift - 1)) | + ((pixel.Blue & mask[level]) >> (shift)); + + OctreeNode child = this._children[index]; + + if (null == child) + { + // Create a new child node & store in the array + child = new OctreeNode(level + 1, colorBits, octree); + this._children[index] = child; + } + + // Add the color to the child node + child.AddColor(pixel, colorBits, level + 1, octree); + } + + } + + /// + /// Get or Sets the next reducible node + /// + public OctreeNode NextReducible + { + get { return _nextReducible; } + set { _nextReducible = value; } + } + + /// + /// Return the child nodes + /// + public OctreeNode[] Children + { + get { return _children; } + } + + /// + /// Reduce this node by removing all of its children + /// + /// The number of leaves removed + public int Reduce() + { + this._red = this._green = this._blue = 0; + int children = 0; + + // Loop through all children and add their information to this node + for (int index = 0; index < 8; index++) + { + if (null != this._children[index]) + { + this._red += this._children[index]._red; + this._green += this._children[index]._green; + this._blue += this._children[index]._blue; + this._pixelCount += this._children[index]._pixelCount; + ++children; + this._children[index] = null; + } + } + + // Now change this to a leaf node + this._leaf = true; + + // Return the number of nodes to decrement the leaf count by + return children - 1; + } + + /// + /// Traverse the tree, building up the color palette + /// + /// The palette + /// The current palette index + public void ConstructPalette(ArrayList palette, ref int paletteIndex) + { + if (_leaf) + { + // Consume the next palette index + _paletteIndex = paletteIndex++; + + // And set the color of the palette entry + palette.Add(Color.FromArgb(_red / _pixelCount, _green / _pixelCount, _blue / _pixelCount)); + } + else + { + // Loop through children looking for leaves + for (int index = 0; index < 8; index++) + { + if (null != _children[index]) + _children[index].ConstructPalette(palette, ref paletteIndex); + } + } + } + + /// + /// Return the palette index for the passed color + /// + public int GetPaletteIndex(Color32 pixel, int level) + { + int paletteIndex = _paletteIndex; + + if (!_leaf) + { + int shift = 7 - level; + int index = ((pixel.Red & mask[level]) >> (shift - 2)) | + ((pixel.Green & mask[level]) >> (shift - 1)) | + ((pixel.Blue & mask[level]) >> (shift)); + + if (null != _children[index]) + { + paletteIndex = _children[index].GetPaletteIndex(pixel, level + 1); + } + else + { + throw new Exception("Didn't expect this!"); + } + } + + return paletteIndex; + } + + /// + /// Increment the pixel count and add to the color information + /// + public void Increment(Color32 pixel) + { + this._pixelCount++; + this._red += pixel.Red; + this._green += pixel.Green; + this._blue += pixel.Blue; + } + + /// + /// Flag indicating that this is a leaf node + /// + private bool _leaf; + + /// + /// Number of pixels in this node + /// + private int _pixelCount; + + /// + /// Red component + /// + private int _red; + + /// + /// Green Component + /// + private int _green; + + /// + /// Blue component + /// + private int _blue; + + /// + /// Pointers to any child nodes + /// + private OctreeNode[] _children; + + /// + /// Pointer to next reducible node + /// + private OctreeNode _nextReducible; + + /// + /// The index of this node in the palette + /// + private int _paletteIndex; + } + } + } +} diff --git a/src/ImageProcessor/Imaging/PaletteQuantizer.cs b/src/ImageProcessor/Imaging/PaletteQuantizer.cs new file mode 100644 index 000000000..b9d929fd7 --- /dev/null +++ b/src/ImageProcessor/Imaging/PaletteQuantizer.cs @@ -0,0 +1,138 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Imaging +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Drawing; + using System.Drawing.Imaging; + using System.Linq; + using System.Text; + + /// + /// Encapsulates methods to calculate the colour palette if an image. + /// http://codebetter.com/brendantompkins/2007/06/14/gif-image-color-quantizer-now-with-safe-goodness/ + /// + internal class PaletteQuantizer : Quantizer + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The color palette to quantize to + /// + /// + /// Palette quantization only requires a single quantization step + /// + public PaletteQuantizer(ArrayList palette) + : base(true) + { + _colorMap = new Hashtable(); + + _colors = new Color[palette.Count]; + palette.CopyTo(_colors); + } + + /// + /// Override this to process the pixel in the second pass of the algorithm + /// + /// The pixel to quantize + /// The quantized value + protected override byte QuantizePixel(Color32 pixel) + { + byte colorIndex = 0; + int colorHash = pixel.ARGB; + + // Check if the color is in the lookup table + if (_colorMap.ContainsKey(colorHash)) + { + colorIndex = (byte)_colorMap[colorHash]; + } + else + { + // Not found - loop through the palette and find the nearest match. + // Firstly check the alpha value - if 0, lookup the transparent color + if (0 == pixel.Alpha) + { + // Transparent. Lookup the first color with an alpha value of 0 + for (int index = 0; index < _colors.Length; index++) + { + if (0 == _colors[index].A) + { + colorIndex = (byte)index; + break; + } + } + } + else + { + // Not transparent... + int leastDistance = int.MaxValue; + int red = pixel.Red; + int green = pixel.Green; + int blue = pixel.Blue; + + // Loop through the entire palette, looking for the closest color match + for (int index = 0; index < _colors.Length; index++) + { + Color paletteColor = _colors[index]; + + int redDistance = paletteColor.R - red; + int greenDistance = paletteColor.G - green; + int blueDistance = paletteColor.B - blue; + + int distance = (redDistance * redDistance) + + (greenDistance * greenDistance) + + (blueDistance * blueDistance); + + if (distance < leastDistance) + { + colorIndex = (byte)index; + leastDistance = distance; + + // And if it's an exact match, exit the loop + if (0 == distance) + { + break; + } + } + } + } + + // Now I have the color, pop it into the hashtable for next time + _colorMap.Add(colorHash, colorIndex); + } + + return colorIndex; + } + + /// + /// Retrieve the palette for the quantized image + /// + /// Any old palette, this is overrwritten + /// The new color palette + protected override ColorPalette GetPalette(ColorPalette palette) + { + for (int index = 0; index < _colors.Length; index++) + { + palette.Entries[index] = _colors[index]; + } + return palette; + } + + /// + /// Lookup table for colors + /// + private Hashtable _colorMap; + + /// + /// List of all colors in the palette + /// + protected Color[] _colors; + } +} diff --git a/src/ImageProcessor/Imaging/Quantizer.cs b/src/ImageProcessor/Imaging/Quantizer.cs new file mode 100644 index 000000000..97fda4b90 --- /dev/null +++ b/src/ImageProcessor/Imaging/Quantizer.cs @@ -0,0 +1,314 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Imaging +{ + #region Using + using System; + using System.Drawing; + using System.Drawing.Imaging; + using System.Runtime.InteropServices; + #endregion + + /// + /// Encapsulates methods to calulate the colour pallete of an image. + /// + internal abstract class Quantizer + { + #region Fields + /// + /// The flag used to indicate whether a single pass or two passes are needed for quantization. + /// + private readonly bool singlePass; + + /// + /// The size in bytes of the 32 bpp Colour structure. + /// + private readonly int pixelSize; + #endregion + + /// + /// Initializes a new instance of the Quantizer class. + /// + /// + /// If set to , then the quantizer will loop through the source pixels once; + /// otherwise, . + /// + protected Quantizer(bool singlePass) + { + this.singlePass = singlePass; + this.pixelSize = Marshal.SizeOf(typeof(Color32)); + } + + /// + /// Quantizes the given Image and returns the resulting output + /// Bitmap. + /// + /// The image to quantize + /// + /// A quantized Bitmap version of the Image + /// + public Bitmap Quantize(Image source) + { + // Get the size of the source image + int height = source.Height; + int width = source.Width; + + // And construct a rectangle from these dimensions + Rectangle bounds = new Rectangle(0, 0, width, height); + + // First off take a 32bpp copy of the image + using (Bitmap copy = new Bitmap(width, height, PixelFormat.Format32bppArgb)) + { + Bitmap output = null; + + // Define a pointer to the bitmap data + BitmapData sourceData = null; + try + { + // And construct an 8bpp version + output = new Bitmap(width, height, PixelFormat.Format8bppIndexed); + + // Now lock the bitmap into memory + using (Graphics graphics = Graphics.FromImage(copy)) + { + graphics.PageUnit = GraphicsUnit.Pixel; + + // Draw the source image onto the copy bitmap, + // which will effect a widening as appropriate. + graphics.DrawImage(source, bounds); + } + + // Get the source image bits and lock into memory + sourceData = copy.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); + + // Call the FirstPass function if not a single pass algorithm. + // For something like an octree quantizer, this will run through + // all image pixels, build a data structure, and create a palette. + if (!this.singlePass) + { + this.FirstPass(sourceData, width, height); + } + + // Then set the colour palette on the output bitmap. I'm passing in the current palette + // as there's no way to construct a new, empty palette. + output.Palette = this.GetPalette(output.Palette); + + // Then call the second pass which actually does the conversion + this.SecondPass(sourceData, output, width, height, bounds); + } + catch + { + if (output != null) + { + output.Dispose(); + } + } + finally + { + // Ensure that the bits are unlocked + copy.UnlockBits(sourceData); + } + + // Last but not least, return the output bitmap + return output; + } + } + + /// + /// Execute the first pass through the pixels in the image + /// + /// The source data + /// The width in pixels of the image + /// The height in pixels of the image + protected virtual void FirstPass(BitmapData sourceData, int width, int height) + { + // Define the source data pointers. The source row is a byte to + // keep addition of the stride value easier (as this is in bytes) + IntPtr sourceRow = sourceData.Scan0; + + // Loop through each row + for (int row = 0; row < height; row++) + { + // Set the source pixel to the first pixel in this row + IntPtr sourcePixel = sourceRow; + + // And loop through each column + for (int col = 0; col < width; col++) + { + this.InitialQuantizePixel(new Color32(sourcePixel)); + sourcePixel = (IntPtr)((int)sourcePixel + this.pixelSize); + } + + // Now I have the pixel, call the FirstPassQuantize function. + // Add the stride to the source row + sourceRow = (IntPtr)((long)sourceRow + sourceData.Stride); + } + } + + /// + /// Execute a second pass through the bitmap + /// + /// The source bitmap, locked into memory + /// The output bitmap + /// The width in pixels of the image + /// The height in pixels of the image + /// The bounding rectangle + protected virtual void SecondPass(BitmapData sourceData, Bitmap output, int width, int height, Rectangle bounds) + { + BitmapData outputData = null; + + try + { + // Lock the output bitmap into memory + outputData = output.LockBits(bounds, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); + + // Define the source data pointers. The source row is a byte to + // keep addition of the stride value easier (as this is in bytes) + IntPtr sourceRow = sourceData.Scan0; + IntPtr sourcePixel = sourceRow; + IntPtr previousPixel = sourcePixel; + + // Now define the destination data pointers + IntPtr destinationRow = outputData.Scan0; + IntPtr destinationPixel = destinationRow; + + // And convert the first pixel, so that I have values going into the loop. + byte pixelValue = this.QuantizePixel(new Color32(sourcePixel)); + + // Assign the value of the first pixel + Marshal.WriteByte(destinationPixel, pixelValue); + + // Loop through each row + for (int row = 0; row < height; row++) + { + // Set the source pixel to the first pixel in this row + sourcePixel = sourceRow; + + // And set the destination pixel pointer to the first pixel in the row + destinationPixel = destinationRow; + + // Loop through each pixel on this scan line + for (int col = 0; col < width; col++) + { + // Check if this is the same as the last pixel. If so use that value + // rather than calculating it again. This is an inexpensive optimisation. + if (Marshal.ReadByte(previousPixel) != Marshal.ReadByte(sourcePixel)) + { + // Quantize the pixel + pixelValue = this.QuantizePixel(new Color32(sourcePixel)); + + // And setup the previous pointer + previousPixel = sourcePixel; + } + + // And set the pixel in the output + Marshal.WriteByte(destinationPixel, pixelValue); + + sourcePixel = (IntPtr)((long)sourcePixel + this.pixelSize); + destinationPixel = (IntPtr)((long)destinationPixel + 1); + } + + // Add the stride to the source row + sourceRow = (IntPtr)((long)sourceRow + sourceData.Stride); + + // And to the destination row + destinationRow = (IntPtr)((long)destinationRow + outputData.Stride); + } + } + finally + { + // Ensure that I unlock the output bits + output.UnlockBits(outputData); + } + } + + /// + /// Override this to process the pixel in the first pass of the algorithm + /// + /// The pixel to quantize + /// + /// This function need only be overridden if your quantize algorithm needs two passes, + /// such as an Octree quantizer. + /// + protected virtual void InitialQuantizePixel(Color32 pixel) + { + } + + /// + /// Override this to process the pixel in the second pass of the algorithm. + /// + /// The pixel to quantize + /// The quantized value. + protected abstract byte QuantizePixel(Color32 pixel); + + /// + /// Retrieve the palette for the quantized image + /// + /// Any old palette, this is overwritten + /// The new colour palette + protected abstract ColorPalette GetPalette(ColorPalette original); + + /// + /// Structure that defines a 32 bpp colour + /// + /// + /// This structure is used to read data from a 32 bits per pixel image + /// in memory, and is ordered in this manner as this is the way that + /// the data is laid out in memory + /// + [StructLayout(LayoutKind.Explicit)] + public struct Color32 + { + /// + /// Holds the blue component of the colour + /// + [FieldOffset(0)] + public byte Blue; + + /// + /// Holds the green component of the colour + /// + [FieldOffset(1)] + public byte Green; + + /// + /// Holds the red component of the colour + /// + [FieldOffset(2)] + public byte Red; + + /// + /// Holds the alpha component of the colour + /// + [FieldOffset(3)] + public byte Alpha; + + /// + /// Permits the color32 to be treated as an int32 + /// + [FieldOffset(0)] + public int ARGB; + + /// + /// Initializes a new instance of the Color32 structure. + /// + /// The pointer to the pixel. + public Color32(IntPtr sourcePixel) + { + this = (Color32)Marshal.PtrToStructure(sourcePixel, typeof(Color32)); + } + + /// + /// Gets the colour for this Color32 object + /// + public Color Color + { + get { return Color.FromArgb(this.Alpha, this.Red, this.Green, this.Blue); } + } + } + } +} diff --git a/src/ImageProcessor/Imaging/ResponseType.cs b/src/ImageProcessor/Imaging/ResponseType.cs new file mode 100644 index 000000000..7ae3748b5 --- /dev/null +++ b/src/ImageProcessor/Imaging/ResponseType.cs @@ -0,0 +1,62 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Imaging +{ + #region Using + using System.ComponentModel; + #endregion + + /// + /// Globally available enumeration which specifies the correct HTTP MIME type of + /// the output stream for different response types. + /// + /// http://en.wikipedia.org/wiki/Internet_media_type"/ + /// + /// + public enum ResponseType + { + #region Image + /// + /// The correct HTTP MIME type of the output stream for bmp images. + /// + [DescriptionAttribute("image/bmp")] + Bmp, + + /// + /// The correct HTTP MIME type of the output stream for gif images. + /// + [DescriptionAttribute("image/gif")] + Gif, + + /// + /// The correct HTTP MIME type of the output stream for jpeg images. + /// + [DescriptionAttribute("image/jpeg")] + Jpeg, + + /// + /// The correct HTTP MIME type of the output stream for png images. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Png", Justification = "File extension name")] + [DescriptionAttribute("image/png")] + Png, + + /// + /// The correct HTTP MIME type of the output stream for svg images. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Svg", Justification = "File extension name")] + [DescriptionAttribute("image/svg+xml")] + Svg, + + /// + /// The correct HTTP MIME type of the output stream for tiff images. + /// + [DescriptionAttribute("image/tiff")] + Tiff, + #endregion + } +} diff --git a/src/ImageProcessor/Processors/Alpha.cs b/src/ImageProcessor/Processors/Alpha.cs new file mode 100644 index 000000000..87d2783b4 --- /dev/null +++ b/src/ImageProcessor/Processors/Alpha.cs @@ -0,0 +1,175 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Processors +{ + #region Using + using System.Collections.Generic; + using System.Drawing; + using System.Drawing.Imaging; + using System.Text.RegularExpressions; + using ImageProcessor.Helpers.Extensions; + #endregion + + /// + /// Encapsulates methods to change the alpha component of the image to effect its transparency. + /// + public class Alpha : IGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// http://stackoverflow.com/a/6400969/427899 + /// + private static readonly Regex QueryRegex = new Regex(@"alpha=\d{1,2}(?!\d)|alpha=100", RegexOptions.Compiled); + + #region IGraphicsProcessor Members + /// + /// Gets the name. + /// + public string Name + { + get + { + return "Alpha"; + } + } + + /// + /// Gets the description. + /// + public string Description + { + get + { + return "Changes the alpha component of the image to effect its transparency."; + } + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets or sets DynamicParameter. + /// + public dynamic DynamicParameter + { + get; + set; + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder + { + get; + private set; + } + + /// + /// Gets or sets any additional settings required by the processor. + /// + public Dictionary Settings + { + get; + set; + } + + /// + /// The position in the original string where the first character of the captured substring was found. + /// + /// + /// The query string to search. + /// + /// + /// The zero-based starting position in the original string where the captured substring was found. + /// + public int MatchRegexIndex(string queryString) + { + int index = 0; + + // Set the sort order to max to allow filtering. + this.SortOrder = int.MaxValue; + + foreach (Match match in this.RegexPattern.Matches(queryString)) + { + if (match.Success) + { + if (index == 0) + { + // Set the index on the first instance only. + this.SortOrder = match.Index; + int percentage = match.Value.ToIntegerArray()[0]; + + this.DynamicParameter = percentage; + } + + index += 1; + } + } + + return this.SortOrder; + } + + /// + /// Processes the image. + /// + /// + /// The the current instance of the class containing + /// the image to process. + /// + /// + /// The processed image from the current instance of the class. + /// + public Image ProcessImage(ImageFactory factory) + { + Bitmap newImage = null; + Image image = factory.Image; + + try + { + int alphaPercent = this.DynamicParameter; + + newImage = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppPArgb) { Tag = image.Tag }; + + ColorMatrix colorMatrix = new ColorMatrix(); + colorMatrix.Matrix00 = colorMatrix.Matrix11 = colorMatrix.Matrix22 = colorMatrix.Matrix44 = 1; + colorMatrix.Matrix33 = (float)alphaPercent / 100; + + using (Graphics graphics = Graphics.FromImage(newImage)) + { + using (ImageAttributes imageAttributes = new ImageAttributes()) + { + imageAttributes.SetColorMatrix(colorMatrix); + + graphics.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, imageAttributes); + + image.Dispose(); + image = newImage; + } + } + } + catch + { + if (newImage != null) + { + newImage.Dispose(); + } + } + + return image; + } + #endregion + } +} diff --git a/src/ImageProcessor/Processors/Crop.cs b/src/ImageProcessor/Processors/Crop.cs new file mode 100644 index 000000000..fb5810989 --- /dev/null +++ b/src/ImageProcessor/Processors/Crop.cs @@ -0,0 +1,210 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Processors +{ + #region Using + using System.Collections.Generic; + using System.Drawing; + using System.Drawing.Drawing2D; + using System.Drawing.Imaging; + using System.Text.RegularExpressions; + using ImageProcessor.Helpers.Extensions; + #endregion + + /// + /// Crops an image to the given directions. + /// + public class Crop : IGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// http://stackoverflow.com/a/6400969/427899 + /// + private static readonly Regex QueryRegex = new Regex(@"crop=\d+-\d+-\d+-\d+", RegexOptions.Compiled); + + #region IGraphicsProcessor Members + /// + /// Gets the name. + /// + public string Name + { + get + { + return "Crop"; + } + } + + /// + /// Gets the description. + /// + public string Description + { + get + { + return "Crops an image to the given directions."; + } + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets or sets DynamicParameter. + /// + public dynamic DynamicParameter + { + get; + set; + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder + { + get; + private set; + } + + /// + /// Gets or sets any additional settings required by the processor. + /// + public Dictionary Settings + { + get; + set; + } + + /// + /// The position in the original string where the first character of the captured substring was found. + /// + /// + /// The query string to search. + /// + /// + /// The zero-based starting position in the original string where the captured substring was found. + /// + public int MatchRegexIndex(string queryString) + { + int index = 0; + + // Set the sort order to max to allow filtering. + this.SortOrder = int.MaxValue; + + foreach (Match match in this.RegexPattern.Matches(queryString)) + { + if (match.Success) + { + if (index == 0) + { + // Set the index on the first instance only. + this.SortOrder = match.Index; + int[] coordinates = match.Value.ToIntegerArray(); + + int x = coordinates[0]; + int y = coordinates[1]; + int width = coordinates[2]; + int height = coordinates[3]; + + Rectangle rectangle = new Rectangle(x, y, width, height); + this.DynamicParameter = rectangle; + } + + index += 1; + } + } + + return this.SortOrder; + } + + /// + /// Processes the image. + /// + /// + /// The the current instance of the class containing + /// the image to process. + /// + /// + /// The processed image from the current instance of the class. + /// + public Image ProcessImage(ImageFactory factory) + { + Bitmap newImage = null; + Image image = factory.Image; + try + { + Rectangle rectangle = this.DynamicParameter; + + int sourceWidth = image.Width; + int sourceHeight = image.Height; + + if (rectangle.X < sourceWidth && rectangle.Y < sourceHeight) + { + if (rectangle.Width > (sourceWidth - rectangle.X)) + { + rectangle.Width = sourceWidth - rectangle.X; + } + + if (rectangle.Height > (sourceHeight - rectangle.Y)) + { + rectangle.Height = sourceHeight - rectangle.Y; + } + + newImage = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppPArgb) { Tag = image.Tag }; + + using (Graphics graphics = Graphics.FromImage(newImage)) + { + graphics.SmoothingMode = SmoothingMode.AntiAlias; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + + // An unwanted border appears when using InterpolationMode.HighQualityBicubic to resize the image + // as the algorithm appears to be pulling averaging detail from surrounding pixels beyond the edge + // of the image. Using the ImageAttributes class to specify that the pixels beyond are simply mirror + // images of the pixels within solves this problem. + using (ImageAttributes wrapMode = new ImageAttributes()) + { + wrapMode.SetWrapMode(WrapMode.TileFlipXY); + graphics.DrawImage( + image, + new Rectangle(0, 0, rectangle.Width, rectangle.Height), + rectangle.X, + rectangle.Y, + rectangle.Width, + rectangle.Height, + GraphicsUnit.Pixel, + wrapMode); + } + + // Reassign the image. + image.Dispose(); + image = newImage; + } + } + } + catch + { + if (newImage != null) + { + newImage.Dispose(); + } + } + + return image; + } + #endregion + } +} diff --git a/src/ImageProcessor/Processors/Filter.cs b/src/ImageProcessor/Processors/Filter.cs new file mode 100644 index 000000000..b3c0d2756 --- /dev/null +++ b/src/ImageProcessor/Processors/Filter.cs @@ -0,0 +1,292 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Processors +{ + #region Using + using System.Collections.Generic; + using System.Drawing; + using System.Drawing.Imaging; + using System.Text.RegularExpressions; + #endregion + + /// + /// Encapsulates methods with which to add filters to an image. + /// + public class Filter : IGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + private static readonly Regex QueryRegex = new Regex(@"filter=(lomograph|polaroid|blackwhite|sepia|greyscale)", RegexOptions.Compiled); + + #region IGraphicsProcessor Members + /// + /// Gets the name. + /// + public string Name + { + get + { + return "Filter"; + } + } + + /// + /// Gets the description. + /// + public string Description + { + get + { + return "Encapsulates methods with which to add filters to an image. e.g polaroid, lomograph"; + } + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets or sets DynamicParameter. + /// + public dynamic DynamicParameter + { + get; + set; + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder + { + get; + private set; + } + + /// + /// Gets or sets any additional settings required by the processor. + /// + public Dictionary Settings + { + get; + set; + } + + /// + /// The position in the original string where the first character of the captured substring was found. + /// + /// + /// The query string to search. + /// + /// + /// The zero-based starting position in the original string where the captured substring was found. + /// + public int MatchRegexIndex(string queryString) + { + int index = 0; + + // Set the sort order to max to allow filtering. + this.SortOrder = int.MaxValue; + + foreach (Match match in this.RegexPattern.Matches(queryString)) + { + if (match.Success) + { + if (index == 0) + { + // Set the index on the first instance only. + this.SortOrder = match.Index; + this.DynamicParameter = match.Value.Split('=')[1]; + } + + index += 1; + } + } + + return this.SortOrder; + } + + /// + /// Processes the image. + /// + /// + /// The the current instance of the class containing + /// the image to process. + /// + /// + /// The processed image from the current instance of the class. + /// + public Image ProcessImage(ImageFactory factory) + { + Bitmap newImage = null; + Image image = factory.Image; + try + { + newImage = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppPArgb) { Tag = image.Tag }; + + ColorMatrix colorMatrix = null; + + switch ((string)this.DynamicParameter) + { + case "polaroid": + colorMatrix = ColorMatrixes.Poloroid; + break; + case "lomograph": + colorMatrix = ColorMatrixes.Lomograph; + break; + case "sepia": + colorMatrix = ColorMatrixes.Sepia; + break; + case "blackwhite": + colorMatrix = ColorMatrixes.BlackWhite; + break; + case "greyscale": + colorMatrix = ColorMatrixes.GreyScale; + break; + } + + using (Graphics graphics = Graphics.FromImage(newImage)) + { + using (ImageAttributes attributes = new ImageAttributes()) + { + if (colorMatrix != null) + { + attributes.SetColorMatrix(colorMatrix); + } + + Rectangle rectangle = new Rectangle(0, 0, image.Width, image.Height); + + graphics.DrawImage(image, rectangle, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes); + } + } + + // Reassign the image. + image.Dispose(); + image = newImage; + } + catch + { + if (newImage != null) + { + newImage.Dispose(); + } + } + + return image; + } + #endregion + + /// + /// A list of available color matrices to apply to an image. + /// + private static class ColorMatrixes + { + /// + /// Gets Sepia. + /// + internal static ColorMatrix Sepia + { + get + { + return new ColorMatrix( + new float[][] + { + new float[] { .393f, .349f, .272f, 0, 0 }, + new float[] { .769f, .686f, .534f, 0, 0 }, + new float[] { .189f, .168f, .131f, 0, 0 }, + new float[] { 0, 0, 0, 1, 0 }, + new float[] { 0, 0, 0, 0, 1 } + }); + } + } + + /// + /// Gets BlackWhite. + /// + internal static ColorMatrix BlackWhite + { + get + { + return new ColorMatrix( + new float[][] + { + new float[] { 1.5f, 1.5f, 1.5f, 0, 0 }, + new float[] { 1.5f, 1.5f, 1.5f, 0, 0 }, + new float[] { 1.5f, 1.5f, 1.5f, 0, 0 }, + new float[] { 0, 0, 0, 1, 0 }, + new float[] { -1, -1, -1, 0, 1 } + }); + } + } + + /// + /// Gets Poloroid. + /// + internal static ColorMatrix Poloroid + { + get + { + return new ColorMatrix( + new float[][] + { + new float[] { 1.438f, -0.062f, -0.062f, 0, 0 }, + new float[] { -0.122f, 1.378f, -0.122f, 0, 0 }, + new float[] { -0.016f, -0.016f, 1.483f, 0, 0 }, + new float[] { 0, 0, 0, 1, 0 }, + new float[] { -0.03f, 0.05f, -0.02f, 0, 1 } + }); + } + } + + /// + /// Gets Lomograph. + /// + internal static ColorMatrix Lomograph + { + get + { + return new ColorMatrix( + new float[][] + { + new float[] { 1.25f, 0, 0, 0, 0 }, + new float[] { 0, 1.25f, 0, 0, 0 }, + new float[] { 0, 0, 0.94f, 0, 0 }, + new float[] { 0, 0, 0, 1, 0 }, + new float[] { 0, 0, 0, 0, 1 } + }); + } + } + + /// + /// Gets GreyScale. + /// + internal static ColorMatrix GreyScale + { + get + { + return new ColorMatrix( + new float[][] + { + new float[] { .33f, .33f, .33f, 0, 0 }, + new float[] { .59f, .59f, .59f, 0, 0 }, + new float[] { .11f, .11f, .11f, 0, 0 }, + new float[] { 0, 0, 0, 1, 0 }, + new float[] { 0, 0, 0, 0, 1 } + }); + } + } + } + } +} diff --git a/src/ImageProcessor/Processors/Format.cs b/src/ImageProcessor/Processors/Format.cs new file mode 100644 index 000000000..f0725d86f --- /dev/null +++ b/src/ImageProcessor/Processors/Format.cs @@ -0,0 +1,159 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Processors +{ + #region Using + using System.Collections.Generic; + using System.Drawing; + using System.Drawing.Imaging; + using System.Text.RegularExpressions; + #endregion + + /// + /// Sets the output of the image to a specific format. + /// + public class Format : IGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + private static readonly Regex QueryRegex = new Regex(@"format=(jpeg|png|bmp|gif)", RegexOptions.Compiled); + + #region IGraphicsProcessor Members + /// + /// Gets the name. + /// + public string Name + { + get + { + return "Format"; + } + } + + /// + /// Gets the description. + /// + public string Description + { + get + { + return "Sets the output of the image to a specific format."; + } + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets or sets DynamicParameter. + /// + public dynamic DynamicParameter + { + get; + set; + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder + { + get; + private set; + } + + /// + /// Gets or sets any additional settings required by the processor. + /// + public Dictionary Settings + { + get; + set; + } + + /// + /// The position in the original string where the first character of the captured substring was found. + /// + /// + /// The query string to search. + /// + /// + /// The zero-based starting position in the original string where the captured substring was found. + /// + public int MatchRegexIndex(string queryString) + { + int index = 0; + + // Set the sort order to max to allow filtering. + this.SortOrder = int.MaxValue; + + foreach (Match match in this.RegexPattern.Matches(queryString)) + { + if (match.Success) + { + if (index == 0) + { + // Set the index on the first instance only. + this.SortOrder = match.Index; + this.DynamicParameter = match.Value.Split('=')[1]; + } + + index += 1; + } + } + + return this.SortOrder; + } + + /// + /// Processes the image. + /// + /// + /// The the current instance of the class containing + /// the image to process. + /// + /// + /// The processed image from the current instance of the class. + /// + public Image ProcessImage(ImageFactory factory) + { + string format = this.DynamicParameter; + ImageFormat imageFormat; + switch (format) + { + case "png": + imageFormat = ImageFormat.Png; + break; + case "bmp": + imageFormat = ImageFormat.Bmp; + break; + case "gif": + imageFormat = ImageFormat.Gif; + break; + default: + // Should be a jpeg. + imageFormat = ImageFormat.Jpeg; + break; + } + + // Set the internal property. + factory.ImageFormat = imageFormat; + + return factory.Image; + } + #endregion + } +} diff --git a/src/ImageProcessor/Processors/IGraphicsProcessor.cs b/src/ImageProcessor/Processors/IGraphicsProcessor.cs new file mode 100644 index 000000000..672bea4ff --- /dev/null +++ b/src/ImageProcessor/Processors/IGraphicsProcessor.cs @@ -0,0 +1,80 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Processors +{ + #region Using + + using System.Collections; + using System.Collections.Generic; + using System.Collections.Specialized; + using System.Drawing; + using System.Text.RegularExpressions; + #endregion + + /// + /// Defines properties and methods for ImageProcessor Plugins. + /// + public interface IGraphicsProcessor + { + #region MetaData + /// + /// Gets the name. + /// + string Name { get; } + + /// + /// Gets the description. + /// + string Description { get; } + #endregion + + /// + /// Gets the regular expression to search strings for. + /// + Regex RegexPattern { get; } + + /// + /// Gets DynamicParameter. + /// + dynamic DynamicParameter { get; } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + int SortOrder { get; } + + /// + /// Gets or sets any additional settings required by the processor. + /// + Dictionary Settings { get; set; } + + #region Methods + /// + /// The position in the original string where the first character of the captured substring was found. + /// + /// + /// The query string to search. + /// + /// + /// The zero-based starting position in the original string where the captured substring was found. + /// + int MatchRegexIndex(string queryString); + + /// + /// Processes the image. + /// + /// + /// The the current instance of the class containing + /// the image to process. + /// + /// + /// The processed image from the current instance of the class. + /// + Image ProcessImage(ImageFactory factory); + #endregion + } +} diff --git a/src/ImageProcessor/Processors/Png8.cs b/src/ImageProcessor/Processors/Png8.cs new file mode 100644 index 000000000..36b44f0b7 --- /dev/null +++ b/src/ImageProcessor/Processors/Png8.cs @@ -0,0 +1,147 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Processors +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Drawing; + using System.Linq; + using System.Text; + using System.Text.RegularExpressions; + using ImageProcessor.Imaging; + + /// + /// TODO: Update summary. + /// + public class Png8 : IGraphicsProcessor + { + #region Implementation of IGraphicsProcessor + + /// + /// Gets the name. + /// + public string Name + { + get + { + throw new NotImplementedException(); + } + } + + /// + /// Gets the description. + /// + public string Description + { + get + { + throw new NotImplementedException(); + } + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + throw new NotImplementedException(); + } + } + + /// + /// Gets DynamicParameter. + /// + public dynamic DynamicParameter + { + get + { + throw new NotImplementedException(); + } + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder + { + get + { + throw new NotImplementedException(); + } + } + + /// + /// Gets or sets any additional settings required by the processor. + /// + public Dictionary Settings + { + get + { + throw new NotImplementedException(); + } + set + { + throw new NotImplementedException(); + } + } + + /// + /// The position in the original string where the first character of the captured substring was found. + /// + /// + /// The query string to search. + /// + /// + /// The zero-based starting position in the original string where the captured substring was found. + /// + public int MatchRegexIndex(string queryString) + { + throw new NotImplementedException(); + } + + /// + /// Processes the image. + /// + /// + /// The the current instance of the class containing + /// the image to process. + /// + /// + /// The processed image from the current instance of the class. + /// + public Image ProcessImage(ImageFactory factory) + { + Bitmap newImage = null; + Image image = factory.Image; + try + { + newImage = new Bitmap(image) { Tag = image.Tag }; + using (Graphics graphics = Graphics.FromImage(newImage)) + { + ArrayList pallete = new ArrayList(); + PaletteQuantizer paletteQuantizer = new PaletteQuantizer(new ArrayList(newImage.Palette.Entries)); + newImage = paletteQuantizer.Quantize(newImage); + } + + } + catch + { + if (newImage != null) + { + newImage.Dispose(); + } + } + + return image; + } + + #endregion + } +} diff --git a/src/ImageProcessor/Processors/Quality.cs b/src/ImageProcessor/Processors/Quality.cs new file mode 100644 index 000000000..2e4dfb66f --- /dev/null +++ b/src/ImageProcessor/Processors/Quality.cs @@ -0,0 +1,142 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Processors +{ + #region Using + using System.Collections.Generic; + using System.Drawing; + using System.Text.RegularExpressions; + using ImageProcessor.Helpers.Extensions; + #endregion + + /// + /// TODO: Update summary. + /// + public class Quality : IGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + private static readonly Regex QueryRegex = new Regex(@"quality=\d{1,2}(?!\d)|quality=100", RegexOptions.Compiled); + + #region IGraphicsProcessor Members + /// + /// Gets the name. + /// + public string Name + { + get + { + return "Quality"; + } + } + + /// + /// Gets the description. + /// + public string Description + { + get + { + return "Sets the the quality output for jpeg images."; + } + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets or sets DynamicParameter. + /// + public dynamic DynamicParameter + { + get; + set; + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder + { + get; + private set; + } + + /// + /// Gets or sets any additional settings required by the processor. + /// + public Dictionary Settings + { + get; + set; + } + + /// + /// The position in the original string where the first character of the captured substring was found. + /// + /// + /// The query string to search. + /// + /// + /// The zero-based starting position in the original string where the captured substring was found. + /// + public int MatchRegexIndex(string queryString) + { + int index = 0; + + // Set the sort order to max to allow filtering. + this.SortOrder = int.MaxValue; + + foreach (Match match in this.RegexPattern.Matches(queryString)) + { + if (match.Success) + { + if (index == 0) + { + // Set the index on the first instance only. + this.SortOrder = match.Index; + int percentage = match.Value.ToIntegerArray()[0]; + + this.DynamicParameter = percentage; + } + + index += 1; + } + } + + return this.SortOrder; + } + + /// + /// Processes the image. + /// + /// + /// The the current instance of the class containing + /// the image to process. + /// + /// + /// The processed image from the current instance of the class. + /// + public Image ProcessImage(ImageFactory factory) + { + // Set the internal property. + factory.JpegQuality = this.DynamicParameter; + + return factory.Image; + } + #endregion + } +} diff --git a/src/ImageProcessor/Processors/Resize.cs b/src/ImageProcessor/Processors/Resize.cs new file mode 100644 index 000000000..8fe518796 --- /dev/null +++ b/src/ImageProcessor/Processors/Resize.cs @@ -0,0 +1,235 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Processors +{ + #region Using + using System; + using System.Collections; + using System.Collections.Generic; + using System.Drawing; + using System.Drawing.Drawing2D; + using System.Drawing.Imaging; + using System.Text.RegularExpressions; + using ImageProcessor.Helpers.Extensions; + #endregion + + /// + /// Resizes an image to the given dimensions. + /// + public class Resize : IGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + private static readonly Regex QueryRegex = new Regex(@"(width|height)=\d+", RegexOptions.Compiled); + + #region IGraphicsProcessor Members + /// + /// Gets the name. + /// + public string Name + { + get + { + return "Resize"; + } + } + + /// + /// Gets the description. + /// + public string Description + { + get + { + return "Resizes an image to the given dimensions."; + } + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets or sets DynamicParameter. + /// + public dynamic DynamicParameter + { + get; + set; + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder + { + get; + private set; + } + + /// + /// Gets or sets any additional settings required by the processor. + /// + public Dictionary Settings + { + get; + set; + } + + /// + /// The position in the original string where the first character of the captured substring was found. + /// + /// + /// The query string to search. + /// + /// + /// The zero-based starting position in the original string where the captured substring was found. + /// + public int MatchRegexIndex(string queryString) + { + int index = 0; + + // Set the sort order to max to allow filtering. + this.SortOrder = int.MaxValue; + Size size = new Size(); + + foreach (Match match in this.RegexPattern.Matches(queryString)) + { + if (match.Success) + { + if (index == 0) + { + // Set the index on the first instance only. + this.SortOrder = match.Index; + } + + if (match.Value.Contains("width")) + { + size.Width = match.Value.ToIntegerArray()[0]; + } + else + { + size.Height = match.Value.ToIntegerArray()[0]; + } + + index += 1; + } + } + + this.DynamicParameter = size; + return this.SortOrder; + } + + /// + /// Processes the image. + /// + /// + /// The the current instance of the class containing + /// the image to process. + /// + /// + /// The processed image from the current instance of the class. + /// + public Image ProcessImage(ImageFactory factory) + { + Bitmap newImage = null; + Image image = factory.Image; + + try + { + int width = this.DynamicParameter.Width ?? 0; + int height = this.DynamicParameter.Height ?? 0; + int sourceWidth = image.Width; + int sourceHeight = image.Height; + int defaultMaxWidth; + int defaultMaxHeight; + int.TryParse(this.Settings["MaxWidth"], out defaultMaxWidth); + int.TryParse(this.Settings["MaxHeight"], out defaultMaxHeight); + int maxWidth = defaultMaxWidth > 0 ? defaultMaxWidth : int.MaxValue; + int maxHeight = defaultMaxHeight > 0 ? defaultMaxHeight : int.MaxValue; + + // If height or width is not passed we assume that the standard ratio is to be kept. + if (height == 0) + { + // Bit of simple fractional maths here. + float percentWidth = Math.Abs(width / (float)sourceWidth); + height = (int)Math.Floor(sourceHeight * percentWidth); + } + + if (width == 0) + { + float percentHeight = Math.Abs(height / (float)sourceHeight); + width = (int)Math.Floor(sourceWidth * percentHeight); + } + + if (width > 0 && height > 0 && width <= maxWidth && height <= maxHeight) + { + newImage = new Bitmap(width, height, PixelFormat.Format32bppPArgb) { Tag = image.Tag }; + + using (Graphics graphics = Graphics.FromImage(newImage)) + { + // We want to use two different blending algorithms for enlargement/shrinking. + // Bicubic is better enlarging for whilst Bilinear is better for shrinking. + // http://www.codinghorror.com/blog/2007/07/better-image-resizing.html + if (image.Width < width && image.Height < height) + { + // We are making it larger. + graphics.SmoothingMode = SmoothingMode.AntiAlias; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + } + else + { + // We are making it smaller. + graphics.SmoothingMode = SmoothingMode.None; + + // Contrary to everything I have read bicubic is producing the best results. + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.PixelOffsetMode = PixelOffsetMode.None; + graphics.CompositingQuality = CompositingQuality.HighSpeed; + } + + // An unwanted border appears when using InterpolationMode.HighQualityBicubic to resize the image + // as the algorithm appears to be pulling averaging detail from surFlooring pixels beyond the edge + // of the image. Using the ImageAttributes class to specify that the pixels beyond are simply mirror + // images of the pixels within solves this problem. + using (ImageAttributes wrapMode = new ImageAttributes()) + { + wrapMode.SetWrapMode(WrapMode.TileFlipXY); + Rectangle destRect = new Rectangle(0, 0, width, height); + graphics.DrawImage(image, destRect, 0, 0, sourceWidth, sourceHeight, GraphicsUnit.Pixel, wrapMode); + } + + // Reassign the image. + image.Dispose(); + image = newImage; + } + } + } + catch + { + if (newImage != null) + { + newImage.Dispose(); + } + } + + return image; + } + + #endregion + } +} diff --git a/src/ImageProcessor/Processors/Vignette.cs b/src/ImageProcessor/Processors/Vignette.cs new file mode 100644 index 000000000..fa1f5d880 --- /dev/null +++ b/src/ImageProcessor/Processors/Vignette.cs @@ -0,0 +1,200 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Processors +{ + #region Using + using System; + using System.Collections.Generic; + using System.Drawing; + using System.Drawing.Drawing2D; + using System.Text.RegularExpressions; + #endregion + + /// + /// Encapsulates methods with which to add a vignette image effect to an image. + /// + public class Vignette : IGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + private static readonly Regex QueryRegex = new Regex(@"vignette=true", RegexOptions.Compiled); + + #region IGraphicsProcessor Members + /// + /// Gets the name. + /// + public string Name + { + get + { + return "Vignette"; + } + } + + /// + /// Gets the description. + /// + public string Description + { + get + { + return "Adds a vignette image effect to the image."; + } + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets or sets DynamicParameter. + /// + public dynamic DynamicParameter + { + get; + set; + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder + { + get; + private set; + } + + /// + /// Gets or sets any additional settings required by the processor. + /// + public Dictionary Settings + { + get; + set; + } + + /// + /// The position in the original string where the first character of the captured substring was found. + /// + /// + /// The query string to search. + /// + /// + /// The zero-based starting position in the original string where the captured substring was found. + /// + public int MatchRegexIndex(string queryString) + { + int index = 0; + + // Set the sort order to max to allow filtering. + this.SortOrder = int.MaxValue; + + foreach (Match match in this.RegexPattern.Matches(queryString)) + { + if (match.Success) + { + if (index == 0) + { + // Set the index on the first instance only. + this.SortOrder = match.Index; + bool doVignette; + this.DynamicParameter = bool.TryParse(match.Value.Split('=')[1], out doVignette); + } + + index += 1; + } + } + + return this.SortOrder; + } + + /// + /// Processes the image. + /// + /// + /// The the current instance of the class containing + /// the image to process. + /// + /// + /// The processed image from the current instance of the class. + /// + public Image ProcessImage(ImageFactory factory) + { + Bitmap newImage = null; + Image image = factory.Image; + + try + { + newImage = new Bitmap(image) { Tag = image.Tag }; + + using (Graphics graphics = Graphics.FromImage(newImage)) + { + Rectangle bounds = new Rectangle(0, 0, newImage.Width, newImage.Height); + Rectangle ellipsebounds = bounds; + + // Increase the rectangle size by the difference between the rectangle dimensions and sqrt(2)/2 * the rectangle dimensions. + // Why sqrt(2)/2? Because the point (sqrt(2)/2, sqrt(2)/2) is the 45 degree angle point on a unit circle. Scaling by the width + // and height gives the distance needed to inflate the rect to make sure it's fully covered. + ellipsebounds.Offset(-ellipsebounds.X, -ellipsebounds.Y); + int x = ellipsebounds.Width - (int)Math.Floor(.70712 * ellipsebounds.Width); + int y = ellipsebounds.Height - (int)Math.Floor(.70712 * ellipsebounds.Height); + ellipsebounds.Inflate(x, y); + + using (GraphicsPath path = new GraphicsPath()) + { + path.AddEllipse(ellipsebounds); + using (PathGradientBrush brush = new PathGradientBrush(path)) + { + // Fill a rectangle with an elliptical gradient brush that goes from white to black. + // Change the colour from white to pure transparent black and from black to pure opaque black. + // This has the effect of painting the far corners black and shade less on the way in to the centre. + brush.WrapMode = WrapMode.Tile; + brush.CenterColor = Color.FromArgb(0, 0, 0, 0); + brush.SurroundColors = new Color[] { Color.FromArgb(255, 0, 0, 0) }; + + Blend blend = new Blend + { + Positions = new float[] { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0F }, + Factors = new float[] { 0.0f, 0.5f, 1f, 1f, 1.0f, 1.0f } + }; + + brush.Blend = blend; + + Region oldClip = graphics.Clip; + graphics.Clip = new Region(bounds); + graphics.FillRectangle(brush, ellipsebounds); + graphics.Clip = oldClip; + } + + // Reassign the image. + image.Dispose(); + image = newImage; + } + } + } + catch + { + if (newImage != null) + { + newImage.Dispose(); + } + } + + return image; + } + #endregion + } +} + diff --git a/src/ImageProcessor/Properties/AssemblyInfo.cs b/src/ImageProcessor/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..20aa364de --- /dev/null +++ b/src/ImageProcessor/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ImageProcessor")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ImageProcessor")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("bdaae9bd-0dc8-4b06-8722-e2e0c9a74301")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Test/Test.sln b/src/Test/Test.sln new file mode 100644 index 000000000..7893f8741 --- /dev/null +++ b/src/Test/Test.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{30327C08-7574-4D7E-AC95-6A58753C6855}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/Test/Test/Content/Site.css b/src/Test/Test/Content/Site.css new file mode 100644 index 000000000..0c669c7de --- /dev/null +++ b/src/Test/Test/Content/Site.css @@ -0,0 +1,324 @@ +/*---------------------------------------------------------- +The base color for this template is #5c87b2. If you'd like +to use a different color start by replacing all instances of +#5c87b2 with your new color. +----------------------------------------------------------*/ +body { + background-color: #5c87b2; + font-size: .85em; + font-family: "Trebuchet MS", Verdana, Helvetica, Sans-Serif; + margin: 0; + padding: 0; + color: #696969; +} + +a:link { + color: #034af3; + text-decoration: underline; +} + +a:visited { + color: #505abc; +} + +a:hover { + color: #1d60ff; + text-decoration: none; +} + +a:active { + color: #12eb87; +} + +p, ul { + margin-bottom: 20px; + line-height: 1.6em; +} + +header, +footer, +nav, +section { + display: block; +} + +/* HEADINGS +----------------------------------------------------------*/ +h1, h2, h3, h4, h5, h6 { + font-size: 1.5em; + color: #000; +} + +h1 { + font-size: 2em; + padding-bottom: 0; + margin-bottom: 0; +} + +h2 { + padding: 0 0 10px 0; +} + +h3 { + font-size: 1.2em; +} + +h4 { + font-size: 1.1em; +} + +h5, h6 { + font-size: 1em; +} + +/* PRIMARY LAYOUT ELEMENTS +----------------------------------------------------------*/ + +/* you can specify a greater or lesser percentage for the +page width. Or, you can specify an exact pixel width. */ +.page { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +header, #header { + position: relative; + margin-bottom: 0px; + color: #000; + padding: 0; +} + +header h1, #header h1 { + font-weight: bold; + padding: 5px 0; + margin: 0; + color: #fff; + border: none; + line-height: 2em; + font-size: 32px !important; + text-shadow: 1px 1px 2px #111; +} + +#main { + padding: 30px 30px 15px 30px; + background-color: #fff; + border-radius: 4px 0 0 0; + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; +} + +footer, +#footer { + background-color: #fff; + color: #999; + padding: 10px 0; + text-align: center; + line-height: normal; + margin: 0 0 30px 0; + font-size: .9em; + border-radius: 0 0 4px 4px; + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; +} + +/* TAB MENU +----------------------------------------------------------*/ +ul#menu { + border-bottom: 1px #5C87B2 solid; + padding: 0 0 2px; + position: relative; + margin: 0; + text-align: right; +} + +ul#menu li { + display: inline; + list-style: none; +} + +ul#menu li#greeting { + padding: 10px 20px; + font-weight: bold; + text-decoration: none; + line-height: 2.8em; + color: #fff; +} + +ul#menu li a { + padding: 10px 20px; + font-weight: bold; + text-decoration: none; + line-height: 2.8em; + background-color: #e8eef4; + color: #034af3; + border-radius: 4px 4px 0 0; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; +} + +ul#menu li a:hover { + background-color: #fff; + text-decoration: none; +} + +ul#menu li a:active { + background-color: #a6e2a6; + text-decoration: none; +} + +ul#menu li.selected a { + background-color: #fff; + color: #000; +} + +/* FORM LAYOUT ELEMENTS +----------------------------------------------------------*/ + +fieldset { + border: 1px solid #ddd; + padding: 0 1.4em 1.4em 1.4em; + margin: 0 0 1.5em 0; +} + +legend { + font-size: 1.2em; + font-weight: bold; +} + +textarea { + min-height: 75px; +} + +input[type="text"], +input[type="password"] { + border: 1px solid #ccc; + padding: 2px; + font-size: 1.2em; + color: #444; + width: 200px; +} + +select { + border: 1px solid #ccc; + padding: 2px; + font-size: 1.2em; + color: #444; +} + +input[type="submit"] { + font-size: 1.2em; + padding: 5px; +} + +/* TABLE +----------------------------------------------------------*/ + +table { + border: solid 1px #e8eef4; + border-collapse: collapse; +} + +table td { + padding: 5px; + border: solid 1px #e8eef4; +} + +table th { + padding: 6px 5px; + text-align: left; + background-color: #e8eef4; + border: solid 1px #e8eef4; +} + +/* MISC +----------------------------------------------------------*/ +.clear { + clear: both; +} + +.error { + color: Red; +} + +nav, +#menucontainer { + margin-top: 40px; +} + +div#title { + display: block; + float: left; + text-align: left; +} + +#logindisplay { + font-size: 1.1em; + display: block; + text-align: right; + margin: 10px; + color: White; +} + +#logindisplay a:link { + color: white; + text-decoration: underline; +} + +#logindisplay a:visited { + color: white; + text-decoration: underline; +} + +#logindisplay a:hover { + color: white; + text-decoration: none; +} + +/* Styles for validation helpers +-----------------------------------------------------------*/ +.field-validation-error { + color: #ff0000; +} + +.field-validation-valid { + display: none; +} + +.input-validation-error { + border: 1px solid #ff0000; + background-color: #ffeeee; +} + +.validation-summary-errors { + font-weight: bold; + color: #ff0000; +} + +.validation-summary-valid { + display: none; +} + +/* Styles for editor and display helpers +----------------------------------------------------------*/ +.display-label, +.editor-label { + margin: 1em 0 0 0; +} + +.display-field, +.editor-field { + margin: 0.5em 0 0 0; +} + +.text-box { + width: 30em; +} + +.text-box.multi-line { + height: 6.5em; +} + +.tri-state { + width: 6em; +} diff --git a/src/Test/Test/Content/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png b/src/Test/Test/Content/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png new file mode 100644 index 0000000000000000000000000000000000000000..5b5dab2ab7b1c50dea9cfe73dc5a269a92d2d4b4 GIT binary patch literal 180 zcmeAS@N?(olHy`uVBq!ia0vp^8bF-F!3HG1q!d*FscKIb$B>N1x91EQ4=4yQ7#`R^ z$vje}bP0l+XkK DSH>_4 literal 0 HcmV?d00001 diff --git a/src/Test/Test/Content/themes/base/images/ui-bg_flat_75_ffffff_40x100.png b/src/Test/Test/Content/themes/base/images/ui-bg_flat_75_ffffff_40x100.png new file mode 100644 index 0000000000000000000000000000000000000000..ac8b229af950c29356abf64a6c4aa894575445f0 GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^8bF-F!3HG1q!d*FsY*{5$B>N1x91EQ4=4yQYz+E8 zPo9&<{J;c_6SHRil>2s{Zw^OT)6@jj2u|u!(plXsM>LJD`vD!n;OXk;vd$@?2>^GI BH@yG= literal 0 HcmV?d00001 diff --git a/src/Test/Test/Content/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png b/src/Test/Test/Content/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..ad3d6346e00f246102f72f2e026ed0491988b394 GIT binary patch literal 120 zcmeAS@N?(olHy`uVBq!ia0vp^j6gJjgAK^akKnour0hLi978O6-<~(*I$*%ybaDOn z{W;e!B}_MSUQoPXhYd^Y6RUoS1yepnPx`2Kz)7OXQG!!=-jY=F+d2OOy?#DnJ32>z UEim$g7SJdLPgg&ebxsLQ09~*s;{X5v literal 0 HcmV?d00001 diff --git a/src/Test/Test/Content/themes/base/images/ui-bg_glass_65_ffffff_1x400.png b/src/Test/Test/Content/themes/base/images/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..42ccba269b6e91bef12ad0fa18be651b5ef0ee68 GIT binary patch literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^j6gJjgAK^akKnouqzpV=978O6-=0?FV^9z|eBtf= z|7WztIJ;WT>{+tN>ySr~=F{k$>;_x^_y?afmf9pRKH0)6?eSP?3s5hEr>mdKI;Vst E0O;M1& literal 0 HcmV?d00001 diff --git a/src/Test/Test/Content/themes/base/images/ui-bg_glass_75_dadada_1x400.png b/src/Test/Test/Content/themes/base/images/ui-bg_glass_75_dadada_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..5a46b47cb16631068aee9e0bd61269fc4e95e5cd GIT binary patch literal 111 zcmeAS@N?(olHy`uVBq!ia0vp^j6gJjgAK^akKnouq|7{B978O6lPf+wIa#m9#>Unb zm^4K~wN3Zq+uP{vDV26o)#~38k_!`W=^oo1w6ixmPC4R1b Tyd6G3lNdZ*{an^LB{Ts5`idse literal 0 HcmV?d00001 diff --git a/src/Test/Test/Content/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/src/Test/Test/Content/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png new file mode 100644 index 0000000000000000000000000000000000000000..7c9fa6c6edcfcdd3e5b77e6f547b719e6fc66e30 GIT binary patch literal 101 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 literal 0 HcmV?d00001 diff --git a/src/Test/Test/Content/themes/base/images/ui-icons_2e83ff_256x240.png b/src/Test/Test/Content/themes/base/images/ui-icons_2e83ff_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..45e8928e5284adacea3f9ec07b9b50667d2ac65f GIT binary patch literal 4369 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 literal 0 HcmV?d00001 diff --git a/src/Test/Test/Content/themes/base/images/ui-icons_454545_256x240.png b/src/Test/Test/Content/themes/base/images/ui-icons_454545_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..7ec70d11bfb2f77374dfd00ef61ba0c3647b5a0c GIT binary patch literal 4369 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 k*Kv;w;*%(i9W@fAqs5i2wiq literal 0 HcmV?d00001 diff --git a/src/Test/Test/Content/themes/base/images/ui-icons_888888_256x240.png b/src/Test/Test/Content/themes/base/images/ui-icons_888888_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..5ba708c39172a69e069136bd1309c4322c61f571 GIT binary patch literal 4369 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 literal 0 HcmV?d00001 diff --git a/src/Test/Test/Content/themes/base/jquery.ui.accordion.css b/src/Test/Test/Content/themes/base/jquery.ui.accordion.css new file mode 100644 index 000000000..4a67cbf8e --- /dev/null +++ b/src/Test/Test/Content/themes/base/jquery.ui.accordion.css @@ -0,0 +1,24 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Accordion 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Accordion#theming + */ +/* IE/Win - Fix animation bug - #4615 */ +.ui-accordion { width: 100%; } +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } +.ui-accordion .ui-accordion-li-fix { display: inline; } +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } +.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } +.ui-accordion .ui-accordion-content-active { display: block; } diff --git a/src/Test/Test/Content/themes/base/jquery.ui.all.css b/src/Test/Test/Content/themes/base/jquery.ui.all.css new file mode 100644 index 000000000..2b2c103e8 --- /dev/null +++ b/src/Test/Test/Content/themes/base/jquery.ui.all.css @@ -0,0 +1,16 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI CSS Framework 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Theming + */ +@import "jquery.ui.base.css"; +@import "jquery.ui.theme.css"; diff --git a/src/Test/Test/Content/themes/base/jquery.ui.autocomplete.css b/src/Test/Test/Content/themes/base/jquery.ui.autocomplete.css new file mode 100644 index 000000000..aac4e204d --- /dev/null +++ b/src/Test/Test/Content/themes/base/jquery.ui.autocomplete.css @@ -0,0 +1,62 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Autocomplete 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * http://docs.jquery.com/UI/Autocomplete#theming + */ +.ui-autocomplete { position: absolute; cursor: default; } + +/* workarounds */ +* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ + +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Menu 1.8.11 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Menu#theming + */ +.ui-menu { + list-style:none; + padding: 2px; + margin: 0; + display:block; + float: left; +} +.ui-menu .ui-menu { + margin-top: -3px; +} +.ui-menu .ui-menu-item { + margin:0; + padding: 0; + zoom: 1; + float: left; + clear: left; + width: 100%; +} +.ui-menu .ui-menu-item a { + text-decoration:none; + display:block; + padding:.2em .4em; + line-height:1.5; + zoom:1; +} +.ui-menu .ui-menu-item a.ui-state-hover, +.ui-menu .ui-menu-item a.ui-state-active { + font-weight: normal; + margin: -1px; +} diff --git a/src/Test/Test/Content/themes/base/jquery.ui.base.css b/src/Test/Test/Content/themes/base/jquery.ui.base.css new file mode 100644 index 000000000..f52ee39b9 --- /dev/null +++ b/src/Test/Test/Content/themes/base/jquery.ui.base.css @@ -0,0 +1,11 @@ +@import url("jquery.ui.core.css"); +@import url("jquery.ui.resizable.css"); +@import url("jquery.ui.selectable.css"); +@import url("jquery.ui.accordion.css"); +@import url("jquery.ui.autocomplete.css"); +@import url("jquery.ui.button.css"); +@import url("jquery.ui.dialog.css"); +@import url("jquery.ui.slider.css"); +@import url("jquery.ui.tabs.css"); +@import url("jquery.ui.datepicker.css"); +@import url("jquery.ui.progressbar.css"); \ No newline at end of file diff --git a/src/Test/Test/Content/themes/base/jquery.ui.button.css b/src/Test/Test/Content/themes/base/jquery.ui.button.css new file mode 100644 index 000000000..af6c985b8 --- /dev/null +++ b/src/Test/Test/Content/themes/base/jquery.ui.button.css @@ -0,0 +1,43 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Button 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Button#theming + */ +.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ +.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ +button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ +.ui-button-icons-only { width: 3.4em; } +button.ui-button-icons-only { width: 3.7em; } + +/*button text element */ +.ui-button .ui-button-text { display: block; line-height: 1.4; } +.ui-button-text-only .ui-button-text { padding: .4em 1em; } +.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } +.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } +.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } +.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } +/* no icon support for input elements, provide padding by default */ +input.ui-button { padding: .4em 1em; } + +/*button icon element(s) */ +.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } +.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } +.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } +.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } +.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } + +/*button sets*/ +.ui-buttonset { margin-right: 7px; } +.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } + +/* workarounds */ +button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ diff --git a/src/Test/Test/Content/themes/base/jquery.ui.core.css b/src/Test/Test/Content/themes/base/jquery.ui.core.css new file mode 100644 index 000000000..55fb8b0d9 --- /dev/null +++ b/src/Test/Test/Content/themes/base/jquery.ui.core.css @@ -0,0 +1,46 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI CSS Framework 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Theming/API + */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } diff --git a/src/Test/Test/Content/themes/base/jquery.ui.datepicker.css b/src/Test/Test/Content/themes/base/jquery.ui.datepicker.css new file mode 100644 index 000000000..7126923cc --- /dev/null +++ b/src/Test/Test/Content/themes/base/jquery.ui.datepicker.css @@ -0,0 +1,73 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Datepicker 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Datepicker#theming + */ +.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + display: none; /*sorry for IE5*/ + display/**/: block; /*sorry for IE5*/ + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +} \ No newline at end of file diff --git a/src/Test/Test/Content/themes/base/jquery.ui.dialog.css b/src/Test/Test/Content/themes/base/jquery.ui.dialog.css new file mode 100644 index 000000000..311dd32e5 --- /dev/null +++ b/src/Test/Test/Content/themes/base/jquery.ui.dialog.css @@ -0,0 +1,26 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Dialog 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Dialog#theming + */ +.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } +.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } +.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } +.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } +.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } +.ui-draggable .ui-dialog-titlebar { cursor: move; } diff --git a/src/Test/Test/Content/themes/base/jquery.ui.progressbar.css b/src/Test/Test/Content/themes/base/jquery.ui.progressbar.css new file mode 100644 index 000000000..6e8718e03 --- /dev/null +++ b/src/Test/Test/Content/themes/base/jquery.ui.progressbar.css @@ -0,0 +1,16 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Progressbar 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Progressbar#theming + */ +.ui-progressbar { height:2em; text-align: left; } +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } \ No newline at end of file diff --git a/src/Test/Test/Content/themes/base/jquery.ui.resizable.css b/src/Test/Test/Content/themes/base/jquery.ui.resizable.css new file mode 100644 index 000000000..bf037be18 --- /dev/null +++ b/src/Test/Test/Content/themes/base/jquery.ui.resizable.css @@ -0,0 +1,25 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Resizable 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)] + * + * http://docs.jquery.com/UI/Resizable#theming + */ +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;} \ No newline at end of file diff --git a/src/Test/Test/Content/themes/base/jquery.ui.selectable.css b/src/Test/Test/Content/themes/base/jquery.ui.selectable.css new file mode 100644 index 000000000..011416b6f --- /dev/null +++ b/src/Test/Test/Content/themes/base/jquery.ui.selectable.css @@ -0,0 +1,15 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Selectable 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Selectable#theming + */ +.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } diff --git a/src/Test/Test/Content/themes/base/jquery.ui.slider.css b/src/Test/Test/Content/themes/base/jquery.ui.slider.css new file mode 100644 index 000000000..3bbfb932d --- /dev/null +++ b/src/Test/Test/Content/themes/base/jquery.ui.slider.css @@ -0,0 +1,29 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Slider 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Slider#theming + */ +.ui-slider { position: relative; text-align: left; } +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } + +.ui-slider-horizontal { height: .8em; } +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: .8em; height: 100px; } +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; } \ No newline at end of file diff --git a/src/Test/Test/Content/themes/base/jquery.ui.tabs.css b/src/Test/Test/Content/themes/base/jquery.ui.tabs.css new file mode 100644 index 000000000..aa5cd8a54 --- /dev/null +++ b/src/Test/Test/Content/themes/base/jquery.ui.tabs.css @@ -0,0 +1,23 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Tabs 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Tabs#theming + */ +.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ +.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } +.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } +.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } +.ui-tabs .ui-tabs-hide { display: none !important; } diff --git a/src/Test/Test/Content/themes/base/jquery.ui.theme.css b/src/Test/Test/Content/themes/base/jquery.ui.theme.css new file mode 100644 index 000000000..0d5b73546 --- /dev/null +++ b/src/Test/Test/Content/themes/base/jquery.ui.theme.css @@ -0,0 +1,257 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI CSS Framework 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Theming/API + * + * To view and modify this theme, visit http://jqueryui.com/themeroller/ + */ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; } +.ui-widget .ui-widget { font-size: 1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; } +.ui-widget-content { border: 1px solid #aaaaaa/*{borderColorContent}*/; background: #ffffff/*{bgColorContent}*/ url(images/ui-bg_flat_75_ffffff_40x100.png)/*{bgImgUrlContent}*/ 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; color: #222222/*{fcContent}*/; } +.ui-widget-content a { color: #222222/*{fcContent}*/; } +.ui-widget-header { border: 1px solid #aaaaaa/*{borderColorHeader}*/; background: #cccccc/*{bgColorHeader}*/ url(images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; color: #222222/*{fcHeader}*/; font-weight: bold; } +.ui-widget-header a { color: #222222/*{fcHeader}*/; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; } +.ui-state-hover a, .ui-state-hover a:hover { color: #212121/*{fcHover}*/; text-decoration: none; } +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; } +.ui-widget :active { outline: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; } +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; } +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a/*{fcError}*/; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; } +.ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; } +.ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; } +.ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; } +.ui-corner-top { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; } +.ui-corner-bottom { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; } +.ui-corner-right { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; } +.ui-corner-left { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; } +.ui-corner-all { -moz-border-radius: 4px/*{cornerRadius}*/; -webkit-border-radius: 4px/*{cornerRadius}*/; border-radius: 4px/*{cornerRadius}*/; } + +/* Overlays */ +.ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; } +.ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; } \ No newline at end of file diff --git a/src/Test/Test/Controllers/AccountController.cs b/src/Test/Test/Controllers/AccountController.cs new file mode 100644 index 000000000..3ec272166 --- /dev/null +++ b/src/Test/Test/Controllers/AccountController.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; +using System.Web.Security; +using Test.Models; + +namespace Test.Controllers +{ + public class AccountController : Controller + { + + // + // GET: /Account/LogOn + + public ActionResult LogOn() + { + return View(); + } + + // + // POST: /Account/LogOn + + [HttpPost] + public ActionResult LogOn(LogOnModel model, string returnUrl) + { + if (ModelState.IsValid) + { + if (Membership.ValidateUser(model.UserName, model.Password)) + { + FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe); + if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") + && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\")) + { + return Redirect(returnUrl); + } + else + { + return RedirectToAction("Index", "Home"); + } + } + else + { + ModelState.AddModelError("", "The user name or password provided is incorrect."); + } + } + + // If we got this far, something failed, redisplay form + return View(model); + } + + // + // GET: /Account/LogOff + + public ActionResult LogOff() + { + FormsAuthentication.SignOut(); + + return RedirectToAction("Index", "Home"); + } + + // + // GET: /Account/Register + + public ActionResult Register() + { + return View(); + } + + // + // POST: /Account/Register + + [HttpPost] + public ActionResult Register(RegisterModel model) + { + if (ModelState.IsValid) + { + // Attempt to register the user + MembershipCreateStatus createStatus; + Membership.CreateUser(model.UserName, model.Password, model.Email, null, null, true, null, out createStatus); + + if (createStatus == MembershipCreateStatus.Success) + { + FormsAuthentication.SetAuthCookie(model.UserName, false /* createPersistentCookie */); + return RedirectToAction("Index", "Home"); + } + else + { + ModelState.AddModelError("", ErrorCodeToString(createStatus)); + } + } + + // If we got this far, something failed, redisplay form + return View(model); + } + + // + // GET: /Account/ChangePassword + + [Authorize] + public ActionResult ChangePassword() + { + return View(); + } + + // + // POST: /Account/ChangePassword + + [Authorize] + [HttpPost] + public ActionResult ChangePassword(ChangePasswordModel model) + { + if (ModelState.IsValid) + { + + // ChangePassword will throw an exception rather + // than return false in certain failure scenarios. + bool changePasswordSucceeded; + try + { + MembershipUser currentUser = Membership.GetUser(User.Identity.Name, true /* userIsOnline */); + changePasswordSucceeded = currentUser.ChangePassword(model.OldPassword, model.NewPassword); + } + catch (Exception) + { + changePasswordSucceeded = false; + } + + if (changePasswordSucceeded) + { + return RedirectToAction("ChangePasswordSuccess"); + } + else + { + ModelState.AddModelError("", "The current password is incorrect or the new password is invalid."); + } + } + + // If we got this far, something failed, redisplay form + return View(model); + } + + // + // GET: /Account/ChangePasswordSuccess + + public ActionResult ChangePasswordSuccess() + { + return View(); + } + + #region Status Codes + private static string ErrorCodeToString(MembershipCreateStatus createStatus) + { + // See http://go.microsoft.com/fwlink/?LinkID=177550 for + // a full list of status codes. + switch (createStatus) + { + case MembershipCreateStatus.DuplicateUserName: + return "User name already exists. Please enter a different user name."; + + case MembershipCreateStatus.DuplicateEmail: + return "A user name for that e-mail address already exists. Please enter a different e-mail address."; + + case MembershipCreateStatus.InvalidPassword: + return "The password provided is invalid. Please enter a valid password value."; + + case MembershipCreateStatus.InvalidEmail: + return "The e-mail address provided is invalid. Please check the value and try again."; + + case MembershipCreateStatus.InvalidAnswer: + return "The password retrieval answer provided is invalid. Please check the value and try again."; + + case MembershipCreateStatus.InvalidQuestion: + return "The password retrieval question provided is invalid. Please check the value and try again."; + + case MembershipCreateStatus.InvalidUserName: + return "The user name provided is invalid. Please check the value and try again."; + + case MembershipCreateStatus.ProviderError: + return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator."; + + case MembershipCreateStatus.UserRejected: + return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator."; + + default: + return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator."; + } + } + #endregion + } +} diff --git a/src/Test/Test/Controllers/HomeController.cs b/src/Test/Test/Controllers/HomeController.cs new file mode 100644 index 000000000..d41ab863e --- /dev/null +++ b/src/Test/Test/Controllers/HomeController.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; + +namespace Test.Controllers +{ + using System.IO; + using System.Threading.Tasks; + using System.Web.Hosting; + + public class HomeController : Controller + { + public ActionResult Index() + { + ViewBag.Message = "Welcome to ASP.NET MVC!"; + + return View(); + } + + public ActionResult About() + { + List images = new List(); + + const string Path = "/images/"; + string folder = HostingEnvironment.MapPath(Path); + if (folder != null) + { + DirectoryInfo directoryInfo = new DirectoryInfo(folder); + + if (directoryInfo.Exists) + { + // Get all the files in the cache ordered by LastAccessTime - oldest first. + List fileInfos = directoryInfo.EnumerateFiles("*", SearchOption.AllDirectories).OrderBy(x => x.LastAccessTime).ToList(); + + int counter = fileInfos.Count; + + Parallel.ForEach( + fileInfos, + fileInfo => images.Add(Path + fileInfo.Name)); + } + } + + return View(images); + } + } +} diff --git a/src/Test/Test/Global.asax b/src/Test/Test/Global.asax new file mode 100644 index 000000000..5798265d5 --- /dev/null +++ b/src/Test/Test/Global.asax @@ -0,0 +1 @@ +<%@ Application Codebehind="Global.asax.cs" Inherits="Test.MvcApplication" Language="C#" %> diff --git a/src/Test/Test/Global.asax.cs b/src/Test/Test/Global.asax.cs new file mode 100644 index 000000000..1d151b372 --- /dev/null +++ b/src/Test/Test/Global.asax.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; + +namespace Test +{ + // Note: For instructions on enabling IIS6 or IIS7 classic mode, + // visit http://go.microsoft.com/?LinkId=9394801 + + public class MvcApplication : System.Web.HttpApplication + { + public static void RegisterGlobalFilters(GlobalFilterCollection filters) + { + filters.Add(new HandleErrorAttribute()); + } + + public static void RegisterRoutes(RouteCollection routes) + { + routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); + + routes.MapRoute( + "Default", // Route name + "{controller}/{action}/{id}", // URL with parameters + new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults + ); + + } + + protected void Application_Start() + { + AreaRegistration.RegisterAllAreas(); + + RegisterGlobalFilters(GlobalFilters.Filters); + RegisterRoutes(RouteTable.Routes); + } + } +} \ No newline at end of file diff --git a/src/Test/Test/Images/1182076_e8c402e938_z.jpg b/src/Test/Test/Images/1182076_e8c402e938_z.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bd2c9b90248231317b880634eac8f98f2dbdf6a7 GIT binary patch literal 51058 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 literal 0 HcmV?d00001 diff --git a/src/Test/Test/Images/6287131503_9b1f82e4f0_b.jpg.REMOVED.git-id b/src/Test/Test/Images/6287131503_9b1f82e4f0_b.jpg.REMOVED.git-id new file mode 100644 index 000000000..0db1445a2 --- /dev/null +++ b/src/Test/Test/Images/6287131503_9b1f82e4f0_b.jpg.REMOVED.git-id @@ -0,0 +1 @@ +4d040d9aa3519b3d2303419d1f03eebebf88e956 \ No newline at end of file diff --git a/src/Test/Test/Images/Chrysanthemum.jpg.REMOVED.git-id b/src/Test/Test/Images/Chrysanthemum.jpg.REMOVED.git-id new file mode 100644 index 000000000..d067665c9 --- /dev/null +++ b/src/Test/Test/Images/Chrysanthemum.jpg.REMOVED.git-id @@ -0,0 +1 @@ +757c2a628dd03b1cbe4b3ef07c153897a702b57a \ No newline at end of file diff --git a/src/Test/Test/Images/Chrysanthemum.png.REMOVED.git-id b/src/Test/Test/Images/Chrysanthemum.png.REMOVED.git-id new file mode 100644 index 000000000..71c0303c0 --- /dev/null +++ b/src/Test/Test/Images/Chrysanthemum.png.REMOVED.git-id @@ -0,0 +1 @@ +acbb9eee53e909814665053e0713335921c7d205 \ No newline at end of file diff --git a/src/Test/Test/Images/Desert.jpg.REMOVED.git-id b/src/Test/Test/Images/Desert.jpg.REMOVED.git-id new file mode 100644 index 000000000..228aac3ab --- /dev/null +++ b/src/Test/Test/Images/Desert.jpg.REMOVED.git-id @@ -0,0 +1 @@ +0b88c91336ff8073f34d21ccd683a01f0e0995da \ No newline at end of file diff --git a/src/Test/Test/Images/Hydrangeas.jpg.REMOVED.git-id b/src/Test/Test/Images/Hydrangeas.jpg.REMOVED.git-id new file mode 100644 index 000000000..90b0b53a0 --- /dev/null +++ b/src/Test/Test/Images/Hydrangeas.jpg.REMOVED.git-id @@ -0,0 +1 @@ +a587c9656db0f4773fbada4807b9377df2216d77 \ No newline at end of file diff --git a/src/Test/Test/Images/Jellyfish.jpg.REMOVED.git-id b/src/Test/Test/Images/Jellyfish.jpg.REMOVED.git-id new file mode 100644 index 000000000..54d26d8dd --- /dev/null +++ b/src/Test/Test/Images/Jellyfish.jpg.REMOVED.git-id @@ -0,0 +1 @@ +fa4fd4110616804c956a8fe4c388700ec4408eef \ No newline at end of file diff --git a/src/Test/Test/Images/Koala.jpg.REMOVED.git-id b/src/Test/Test/Images/Koala.jpg.REMOVED.git-id new file mode 100644 index 000000000..e2ff22b20 --- /dev/null +++ b/src/Test/Test/Images/Koala.jpg.REMOVED.git-id @@ -0,0 +1 @@ +78704a099bad91c76ecb96417137464b0fa96b28 \ No newline at end of file diff --git a/src/Test/Test/Images/Lighthouse.jpg.REMOVED.git-id b/src/Test/Test/Images/Lighthouse.jpg.REMOVED.git-id new file mode 100644 index 000000000..66c1485a3 --- /dev/null +++ b/src/Test/Test/Images/Lighthouse.jpg.REMOVED.git-id @@ -0,0 +1 @@ +494be09b8b43cfce7550ba6d54ff3cf799e4c315 \ No newline at end of file diff --git a/src/Test/Test/Images/MSwanson - Wide Large - Rock 02.jpg.REMOVED.git-id b/src/Test/Test/Images/MSwanson - Wide Large - Rock 02.jpg.REMOVED.git-id new file mode 100644 index 000000000..41c6c25df --- /dev/null +++ b/src/Test/Test/Images/MSwanson - Wide Large - Rock 02.jpg.REMOVED.git-id @@ -0,0 +1 @@ +33b6912af301bf216ee81d82b2c3ce6c49e03021 \ No newline at end of file diff --git a/src/Test/Test/Images/Penguins.jpg.REMOVED.git-id b/src/Test/Test/Images/Penguins.jpg.REMOVED.git-id new file mode 100644 index 000000000..ad4371113 --- /dev/null +++ b/src/Test/Test/Images/Penguins.jpg.REMOVED.git-id @@ -0,0 +1 @@ +030ab8a685bebb796c24cc710edd9e69859164f6 \ No newline at end of file diff --git a/src/Test/Test/Images/Tulips.jpg.REMOVED.git-id b/src/Test/Test/Images/Tulips.jpg.REMOVED.git-id new file mode 100644 index 000000000..84b9aff85 --- /dev/null +++ b/src/Test/Test/Images/Tulips.jpg.REMOVED.git-id @@ -0,0 +1 @@ +54c51eb6a86f31a42433b8167470fb18dad32c7d \ No newline at end of file diff --git a/src/Test/Test/Images/fid11246.jpg.REMOVED.git-id b/src/Test/Test/Images/fid11246.jpg.REMOVED.git-id new file mode 100644 index 000000000..4098eb2bc --- /dev/null +++ b/src/Test/Test/Images/fid11246.jpg.REMOVED.git-id @@ -0,0 +1 @@ +30b51f2b174d67995deb595343e3cef4483d64e4 \ No newline at end of file diff --git a/src/Test/Test/Images/fid9141.jpg.REMOVED.git-id b/src/Test/Test/Images/fid9141.jpg.REMOVED.git-id new file mode 100644 index 000000000..f51c8806e --- /dev/null +++ b/src/Test/Test/Images/fid9141.jpg.REMOVED.git-id @@ -0,0 +1 @@ +f945a806925fa3a763bfd4ec421134c217c46494 \ No newline at end of file diff --git a/src/Test/Test/Images/war_horse_quad.jpg.REMOVED.git-id b/src/Test/Test/Images/war_horse_quad.jpg.REMOVED.git-id new file mode 100644 index 000000000..4118c18e4 --- /dev/null +++ b/src/Test/Test/Images/war_horse_quad.jpg.REMOVED.git-id @@ -0,0 +1 @@ +c274f9d59c7f206c1cdf0cf97fd0cc13fc443191 \ No newline at end of file diff --git a/src/Test/Test/Models/AccountModels.cs b/src/Test/Test/Models/AccountModels.cs new file mode 100644 index 000000000..d78c76472 --- /dev/null +++ b/src/Test/Test/Models/AccountModels.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Globalization; +using System.Web.Mvc; +using System.Web.Security; + +namespace Test.Models +{ + + public class ChangePasswordModel + { + [Required] + [DataType(DataType.Password)] + [Display(Name = "Current password")] + public string OldPassword { get; set; } + + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "New password")] + public string NewPassword { get; set; } + + [DataType(DataType.Password)] + [Display(Name = "Confirm new password")] + [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } + } + + public class LogOnModel + { + [Required] + [Display(Name = "User name")] + public string UserName { get; set; } + + [Required] + [DataType(DataType.Password)] + [Display(Name = "Password")] + public string Password { get; set; } + + [Display(Name = "Remember me?")] + public bool RememberMe { get; set; } + } + + public class RegisterModel + { + [Required] + [Display(Name = "User name")] + public string UserName { get; set; } + + [Required] + [DataType(DataType.EmailAddress)] + [Display(Name = "Email address")] + public string Email { get; set; } + + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "Password")] + public string Password { get; set; } + + [DataType(DataType.Password)] + [Display(Name = "Confirm password")] + [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } + } +} diff --git a/src/Test/Test/Properties/AssemblyInfo.cs b/src/Test/Test/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..499251b9f --- /dev/null +++ b/src/Test/Test/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Test")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("34f4c859-67cc-40d2-97ae-27e8c7157052")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Test/Test/Scripts/MicrosoftAjax.debug.js.REMOVED.git-id b/src/Test/Test/Scripts/MicrosoftAjax.debug.js.REMOVED.git-id new file mode 100644 index 000000000..6d7cfd091 --- /dev/null +++ b/src/Test/Test/Scripts/MicrosoftAjax.debug.js.REMOVED.git-id @@ -0,0 +1 @@ +a5f7942ef2b6b06e3c1aac2110fe7e5a1d88bf51 \ No newline at end of file diff --git a/src/Test/Test/Scripts/MicrosoftAjax.js.REMOVED.git-id b/src/Test/Test/Scripts/MicrosoftAjax.js.REMOVED.git-id new file mode 100644 index 000000000..21e699e8d --- /dev/null +++ b/src/Test/Test/Scripts/MicrosoftAjax.js.REMOVED.git-id @@ -0,0 +1 @@ +52e6626a072ad18c35926f81b94995a0c5eeee31 \ No newline at end of file diff --git a/src/Test/Test/Scripts/MicrosoftMvcAjax.debug.js b/src/Test/Test/Scripts/MicrosoftMvcAjax.debug.js new file mode 100644 index 000000000..eb68ba7e7 --- /dev/null +++ b/src/Test/Test/Scripts/MicrosoftMvcAjax.debug.js @@ -0,0 +1,408 @@ +//!---------------------------------------------------------- +//! Copyright (C) Microsoft Corporation. All rights reserved. +//!---------------------------------------------------------- +//! MicrosoftMvcAjax.js + +Type.registerNamespace('Sys.Mvc'); + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.AjaxOptions + +Sys.Mvc.$create_AjaxOptions = function Sys_Mvc_AjaxOptions() { return {}; } + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.InsertionMode + +Sys.Mvc.InsertionMode = function() { + /// + /// + /// + /// + /// + /// +}; +Sys.Mvc.InsertionMode.prototype = { + replace: 0, + insertBefore: 1, + insertAfter: 2 +} +Sys.Mvc.InsertionMode.registerEnum('Sys.Mvc.InsertionMode', false); + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.AjaxContext + +Sys.Mvc.AjaxContext = function Sys_Mvc_AjaxContext(request, updateTarget, loadingElement, insertionMode) { + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + this._request = request; + this._updateTarget = updateTarget; + this._loadingElement = loadingElement; + this._insertionMode = insertionMode; +} +Sys.Mvc.AjaxContext.prototype = { + _insertionMode: 0, + _loadingElement: null, + _response: null, + _request: null, + _updateTarget: null, + + get_data: function Sys_Mvc_AjaxContext$get_data() { + /// + if (this._response) { + return this._response.get_responseData(); + } + else { + return null; + } + }, + + get_insertionMode: function Sys_Mvc_AjaxContext$get_insertionMode() { + /// + return this._insertionMode; + }, + + get_loadingElement: function Sys_Mvc_AjaxContext$get_loadingElement() { + /// + return this._loadingElement; + }, + + get_object: function Sys_Mvc_AjaxContext$get_object() { + /// + var executor = this.get_response(); + return (executor) ? executor.get_object() : null; + }, + + get_response: function Sys_Mvc_AjaxContext$get_response() { + /// + return this._response; + }, + set_response: function Sys_Mvc_AjaxContext$set_response(value) { + /// + this._response = value; + return value; + }, + + get_request: function Sys_Mvc_AjaxContext$get_request() { + /// + return this._request; + }, + + get_updateTarget: function Sys_Mvc_AjaxContext$get_updateTarget() { + /// + return this._updateTarget; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.AsyncHyperlink + +Sys.Mvc.AsyncHyperlink = function Sys_Mvc_AsyncHyperlink() { +} +Sys.Mvc.AsyncHyperlink.handleClick = function Sys_Mvc_AsyncHyperlink$handleClick(anchor, evt, ajaxOptions) { + /// + /// + /// + /// + /// + /// + evt.preventDefault(); + Sys.Mvc.MvcHelpers._asyncRequest(anchor.href, 'post', '', anchor, ajaxOptions); +} + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.MvcHelpers + +Sys.Mvc.MvcHelpers = function Sys_Mvc_MvcHelpers() { +} +Sys.Mvc.MvcHelpers._serializeSubmitButton = function Sys_Mvc_MvcHelpers$_serializeSubmitButton(element, offsetX, offsetY) { + /// + /// + /// + /// + /// + /// + /// + if (element.disabled) { + return null; + } + var name = element.name; + if (name) { + var tagName = element.tagName.toUpperCase(); + var encodedName = encodeURIComponent(name); + var inputElement = element; + if (tagName === 'INPUT') { + var type = inputElement.type; + if (type === 'submit') { + return encodedName + '=' + encodeURIComponent(inputElement.value); + } + else if (type === 'image') { + return encodedName + '.x=' + offsetX + '&' + encodedName + '.y=' + offsetY; + } + } + else if ((tagName === 'BUTTON') && (name.length) && (inputElement.type === 'submit')) { + return encodedName + '=' + encodeURIComponent(inputElement.value); + } + } + return null; +} +Sys.Mvc.MvcHelpers._serializeForm = function Sys_Mvc_MvcHelpers$_serializeForm(form) { + /// + /// + /// + var formElements = form.elements; + var formBody = new Sys.StringBuilder(); + var count = formElements.length; + for (var i = 0; i < count; i++) { + var element = formElements[i]; + var name = element.name; + if (!name || !name.length) { + continue; + } + var tagName = element.tagName.toUpperCase(); + if (tagName === 'INPUT') { + var inputElement = element; + var type = inputElement.type; + if ((type === 'text') || (type === 'password') || (type === 'hidden') || (((type === 'checkbox') || (type === 'radio')) && element.checked)) { + formBody.append(encodeURIComponent(name)); + formBody.append('='); + formBody.append(encodeURIComponent(inputElement.value)); + formBody.append('&'); + } + } + else if (tagName === 'SELECT') { + var selectElement = element; + var optionCount = selectElement.options.length; + for (var j = 0; j < optionCount; j++) { + var optionElement = selectElement.options[j]; + if (optionElement.selected) { + formBody.append(encodeURIComponent(name)); + formBody.append('='); + formBody.append(encodeURIComponent(optionElement.value)); + formBody.append('&'); + } + } + } + else if (tagName === 'TEXTAREA') { + formBody.append(encodeURIComponent(name)); + formBody.append('='); + formBody.append(encodeURIComponent((element.value))); + formBody.append('&'); + } + } + var additionalInput = form._additionalInput; + if (additionalInput) { + formBody.append(additionalInput); + formBody.append('&'); + } + return formBody.toString(); +} +Sys.Mvc.MvcHelpers._asyncRequest = function Sys_Mvc_MvcHelpers$_asyncRequest(url, verb, body, triggerElement, ajaxOptions) { + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + if (ajaxOptions.confirm) { + if (!confirm(ajaxOptions.confirm)) { + return; + } + } + if (ajaxOptions.url) { + url = ajaxOptions.url; + } + if (ajaxOptions.httpMethod) { + verb = ajaxOptions.httpMethod; + } + if (body.length > 0 && !body.endsWith('&')) { + body += '&'; + } + body += 'X-Requested-With=XMLHttpRequest'; + var upperCaseVerb = verb.toUpperCase(); + var isGetOrPost = (upperCaseVerb === 'GET' || upperCaseVerb === 'POST'); + if (!isGetOrPost) { + body += '&'; + body += 'X-HTTP-Method-Override=' + upperCaseVerb; + } + var requestBody = ''; + if (upperCaseVerb === 'GET' || upperCaseVerb === 'DELETE') { + if (url.indexOf('?') > -1) { + if (!url.endsWith('&')) { + url += '&'; + } + url += body; + } + else { + url += '?'; + url += body; + } + } + else { + requestBody = body; + } + var request = new Sys.Net.WebRequest(); + request.set_url(url); + if (isGetOrPost) { + request.set_httpVerb(verb); + } + else { + request.set_httpVerb('POST'); + request.get_headers()['X-HTTP-Method-Override'] = upperCaseVerb; + } + request.set_body(requestBody); + if (verb.toUpperCase() === 'PUT') { + request.get_headers()['Content-Type'] = 'application/x-www-form-urlencoded;'; + } + request.get_headers()['X-Requested-With'] = 'XMLHttpRequest'; + var updateElement = null; + if (ajaxOptions.updateTargetId) { + updateElement = $get(ajaxOptions.updateTargetId); + } + var loadingElement = null; + if (ajaxOptions.loadingElementId) { + loadingElement = $get(ajaxOptions.loadingElementId); + } + var ajaxContext = new Sys.Mvc.AjaxContext(request, updateElement, loadingElement, ajaxOptions.insertionMode); + var continueRequest = true; + if (ajaxOptions.onBegin) { + continueRequest = ajaxOptions.onBegin(ajaxContext) !== false; + } + if (loadingElement) { + Sys.UI.DomElement.setVisible(ajaxContext.get_loadingElement(), true); + } + if (continueRequest) { + request.add_completed(Function.createDelegate(null, function(executor) { + Sys.Mvc.MvcHelpers._onComplete(request, ajaxOptions, ajaxContext); + })); + request.invoke(); + } +} +Sys.Mvc.MvcHelpers._onComplete = function Sys_Mvc_MvcHelpers$_onComplete(request, ajaxOptions, ajaxContext) { + /// + /// + /// + /// + /// + /// + ajaxContext.set_response(request.get_executor()); + if (ajaxOptions.onComplete && ajaxOptions.onComplete(ajaxContext) === false) { + return; + } + var statusCode = ajaxContext.get_response().get_statusCode(); + if ((statusCode >= 200 && statusCode < 300) || statusCode === 304 || statusCode === 1223) { + if (statusCode !== 204 && statusCode !== 304 && statusCode !== 1223) { + var contentType = ajaxContext.get_response().getResponseHeader('Content-Type'); + if ((contentType) && (contentType.indexOf('application/x-javascript') !== -1)) { + eval(ajaxContext.get_data()); + } + else { + Sys.Mvc.MvcHelpers.updateDomElement(ajaxContext.get_updateTarget(), ajaxContext.get_insertionMode(), ajaxContext.get_data()); + } + } + if (ajaxOptions.onSuccess) { + ajaxOptions.onSuccess(ajaxContext); + } + } + else { + if (ajaxOptions.onFailure) { + ajaxOptions.onFailure(ajaxContext); + } + } + if (ajaxContext.get_loadingElement()) { + Sys.UI.DomElement.setVisible(ajaxContext.get_loadingElement(), false); + } +} +Sys.Mvc.MvcHelpers.updateDomElement = function Sys_Mvc_MvcHelpers$updateDomElement(target, insertionMode, content) { + /// + /// + /// + /// + /// + /// + if (target) { + switch (insertionMode) { + case Sys.Mvc.InsertionMode.replace: + target.innerHTML = content; + break; + case Sys.Mvc.InsertionMode.insertBefore: + if (content && content.length > 0) { + target.innerHTML = content + target.innerHTML.trimStart(); + } + break; + case Sys.Mvc.InsertionMode.insertAfter: + if (content && content.length > 0) { + target.innerHTML = target.innerHTML.trimEnd() + content; + } + break; + } + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.AsyncForm + +Sys.Mvc.AsyncForm = function Sys_Mvc_AsyncForm() { +} +Sys.Mvc.AsyncForm.handleClick = function Sys_Mvc_AsyncForm$handleClick(form, evt) { + /// + /// + /// + /// + var additionalInput = Sys.Mvc.MvcHelpers._serializeSubmitButton(evt.target, evt.offsetX, evt.offsetY); + form._additionalInput = additionalInput; +} +Sys.Mvc.AsyncForm.handleSubmit = function Sys_Mvc_AsyncForm$handleSubmit(form, evt, ajaxOptions) { + /// + /// + /// + /// + /// + /// + evt.preventDefault(); + var validationCallbacks = form.validationCallbacks; + if (validationCallbacks) { + for (var i = 0; i < validationCallbacks.length; i++) { + var callback = validationCallbacks[i]; + if (!callback()) { + return; + } + } + } + var body = Sys.Mvc.MvcHelpers._serializeForm(form); + Sys.Mvc.MvcHelpers._asyncRequest(form.action, form.method || 'post', body, form, ajaxOptions); +} + + +Sys.Mvc.AjaxContext.registerClass('Sys.Mvc.AjaxContext'); +Sys.Mvc.AsyncHyperlink.registerClass('Sys.Mvc.AsyncHyperlink'); +Sys.Mvc.MvcHelpers.registerClass('Sys.Mvc.MvcHelpers'); +Sys.Mvc.AsyncForm.registerClass('Sys.Mvc.AsyncForm'); + +// ---- Do not remove this footer ---- +// Generated using Script# v0.5.0.0 (http://projects.nikhilk.net) +// ----------------------------------- diff --git a/src/Test/Test/Scripts/MicrosoftMvcAjax.js b/src/Test/Test/Scripts/MicrosoftMvcAjax.js new file mode 100644 index 000000000..c5a6165e7 --- /dev/null +++ b/src/Test/Test/Scripts/MicrosoftMvcAjax.js @@ -0,0 +1,25 @@ +//---------------------------------------------------------- +// Copyright (C) Microsoft Corporation. All rights reserved. +//---------------------------------------------------------- +// MicrosoftMvcAjax.js + +Type.registerNamespace('Sys.Mvc');Sys.Mvc.$create_AjaxOptions=function(){return {};} +Sys.Mvc.InsertionMode=function(){};Sys.Mvc.InsertionMode.prototype = {replace:0,insertBefore:1,insertAfter:2} +Sys.Mvc.InsertionMode.registerEnum('Sys.Mvc.InsertionMode',false);Sys.Mvc.AjaxContext=function(request,updateTarget,loadingElement,insertionMode){this.$3=request;this.$4=updateTarget;this.$1=loadingElement;this.$0=insertionMode;} +Sys.Mvc.AjaxContext.prototype={$0:0,$1:null,$2:null,$3:null,$4:null,get_data:function(){if(this.$2){return this.$2.get_responseData();}else{return null;}},get_insertionMode:function(){return this.$0;},get_loadingElement:function(){return this.$1;},get_object:function(){var $0=this.get_response();return ($0)?$0.get_object():null;},get_response:function(){return this.$2;},set_response:function(value){this.$2=value;return value;},get_request:function(){return this.$3;},get_updateTarget:function(){return this.$4;}} +Sys.Mvc.AsyncHyperlink=function(){} +Sys.Mvc.AsyncHyperlink.handleClick=function(anchor,evt,ajaxOptions){evt.preventDefault();Sys.Mvc.MvcHelpers.$2(anchor.href,'post','',anchor,ajaxOptions);} +Sys.Mvc.MvcHelpers=function(){} +Sys.Mvc.MvcHelpers.$0=function($p0,$p1,$p2){if($p0.disabled){return null;}var $0=$p0.name;if($0){var $1=$p0.tagName.toUpperCase();var $2=encodeURIComponent($0);var $3=$p0;if($1==='INPUT'){var $4=$3.type;if($4==='submit'){return $2+'='+encodeURIComponent($3.value);}else if($4==='image'){return $2+'.x='+$p1+'&'+$2+'.y='+$p2;}}else if(($1==='BUTTON')&&($0.length)&&($3.type==='submit')){return $2+'='+encodeURIComponent($3.value);}}return null;} +Sys.Mvc.MvcHelpers.$1=function($p0){var $0=$p0.elements;var $1=new Sys.StringBuilder();var $2=$0.length;for(var $4=0;$4<$2;$4++){var $5=$0[$4];var $6=$5.name;if(!$6||!$6.length){continue;}var $7=$5.tagName.toUpperCase();if($7==='INPUT'){var $8=$5;var $9=$8.type;if(($9==='text')||($9==='password')||($9==='hidden')||((($9==='checkbox')||($9==='radio'))&&$5.checked)){$1.append(encodeURIComponent($6));$1.append('=');$1.append(encodeURIComponent($8.value));$1.append('&');}}else if($7==='SELECT'){var $A=$5;var $B=$A.options.length;for(var $C=0;$C<$B;$C++){var $D=$A.options[$C];if($D.selected){$1.append(encodeURIComponent($6));$1.append('=');$1.append(encodeURIComponent($D.value));$1.append('&');}}}else if($7==='TEXTAREA'){$1.append(encodeURIComponent($6));$1.append('=');$1.append(encodeURIComponent(($5.value)));$1.append('&');}}var $3=$p0._additionalInput;if($3){$1.append($3);$1.append('&');}return $1.toString();} +Sys.Mvc.MvcHelpers.$2=function($p0,$p1,$p2,$p3,$p4){if($p4.confirm){if(!confirm($p4.confirm)){return;}}if($p4.url){$p0=$p4.url;}if($p4.httpMethod){$p1=$p4.httpMethod;}if($p2.length>0&&!$p2.endsWith('&')){$p2+='&';}$p2+='X-Requested-With=XMLHttpRequest';var $0=$p1.toUpperCase();var $1=($0==='GET'||$0==='POST');if(!$1){$p2+='&';$p2+='X-HTTP-Method-Override='+$0;}var $2='';if($0==='GET'||$0==='DELETE'){if($p0.indexOf('?')>-1){if(!$p0.endsWith('&')){$p0+='&';}$p0+=$p2;}else{$p0+='?';$p0+=$p2;}}else{$2=$p2;}var $3=new Sys.Net.WebRequest();$3.set_url($p0);if($1){$3.set_httpVerb($p1);}else{$3.set_httpVerb('POST');$3.get_headers()['X-HTTP-Method-Override']=$0;}$3.set_body($2);if($p1.toUpperCase()==='PUT'){$3.get_headers()['Content-Type']='application/x-www-form-urlencoded;';}$3.get_headers()['X-Requested-With']='XMLHttpRequest';var $4=null;if($p4.updateTargetId){$4=$get($p4.updateTargetId);}var $5=null;if($p4.loadingElementId){$5=$get($p4.loadingElementId);}var $6=new Sys.Mvc.AjaxContext($3,$4,$5,$p4.insertionMode);var $7=true;if($p4.onBegin){$7=$p4.onBegin($6)!==false;}if($5){Sys.UI.DomElement.setVisible($6.get_loadingElement(),true);}if($7){$3.add_completed(Function.createDelegate(null,function($p1_0){ +Sys.Mvc.MvcHelpers.$3($3,$p4,$6);}));$3.invoke();}} +Sys.Mvc.MvcHelpers.$3=function($p0,$p1,$p2){$p2.set_response($p0.get_executor());if($p1.onComplete&&$p1.onComplete($p2)===false){return;}var $0=$p2.get_response().get_statusCode();if(($0>=200&&$0<300)||$0===304||$0===1223){if($0!==204&&$0!==304&&$0!==1223){var $1=$p2.get_response().getResponseHeader('Content-Type');if(($1)&&($1.indexOf('application/x-javascript')!==-1)){eval($p2.get_data());}else{Sys.Mvc.MvcHelpers.updateDomElement($p2.get_updateTarget(),$p2.get_insertionMode(),$p2.get_data());}}if($p1.onSuccess){$p1.onSuccess($p2);}}else{if($p1.onFailure){$p1.onFailure($p2);}}if($p2.get_loadingElement()){Sys.UI.DomElement.setVisible($p2.get_loadingElement(),false);}} +Sys.Mvc.MvcHelpers.updateDomElement=function(target,insertionMode,content){if(target){switch(insertionMode){case 0:target.innerHTML=content;break;case 1:if(content&&content.length>0){target.innerHTML=content+target.innerHTML.trimStart();}break;case 2:if(content&&content.length>0){target.innerHTML=target.innerHTML.trimEnd()+content;}break;}}} +Sys.Mvc.AsyncForm=function(){} +Sys.Mvc.AsyncForm.handleClick=function(form,evt){var $0=Sys.Mvc.MvcHelpers.$0(evt.target,evt.offsetX,evt.offsetY);form._additionalInput = $0;} +Sys.Mvc.AsyncForm.handleSubmit=function(form,evt,ajaxOptions){evt.preventDefault();var $0=form.validationCallbacks;if($0){for(var $2=0;$2<$0.length;$2++){var $3=$0[$2];if(!$3()){return;}}}var $1=Sys.Mvc.MvcHelpers.$1(form);Sys.Mvc.MvcHelpers.$2(form.action,form.method||'post',$1,form,ajaxOptions);} +Sys.Mvc.AjaxContext.registerClass('Sys.Mvc.AjaxContext');Sys.Mvc.AsyncHyperlink.registerClass('Sys.Mvc.AsyncHyperlink');Sys.Mvc.MvcHelpers.registerClass('Sys.Mvc.MvcHelpers');Sys.Mvc.AsyncForm.registerClass('Sys.Mvc.AsyncForm'); +// ---- Do not remove this footer ---- +// Generated using Script# v0.5.0.0 (http://projects.nikhilk.net) +// ----------------------------------- diff --git a/src/Test/Test/Scripts/MicrosoftMvcValidation.debug.js b/src/Test/Test/Scripts/MicrosoftMvcValidation.debug.js new file mode 100644 index 000000000..346ba4818 --- /dev/null +++ b/src/Test/Test/Scripts/MicrosoftMvcValidation.debug.js @@ -0,0 +1,883 @@ +//!---------------------------------------------------------- +//! Copyright (C) Microsoft Corporation. All rights reserved. +//!---------------------------------------------------------- +//! MicrosoftMvcValidation.js + + +Type.registerNamespace('Sys.Mvc'); + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.Validation + +Sys.Mvc.$create_Validation = function Sys_Mvc_Validation() { return {}; } + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.JsonValidationField + +Sys.Mvc.$create_JsonValidationField = function Sys_Mvc_JsonValidationField() { return {}; } + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.JsonValidationOptions + +Sys.Mvc.$create_JsonValidationOptions = function Sys_Mvc_JsonValidationOptions() { return {}; } + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.JsonValidationRule + +Sys.Mvc.$create_JsonValidationRule = function Sys_Mvc_JsonValidationRule() { return {}; } + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.ValidationContext + +Sys.Mvc.$create_ValidationContext = function Sys_Mvc_ValidationContext() { return {}; } + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.NumberValidator + +Sys.Mvc.NumberValidator = function Sys_Mvc_NumberValidator() { +} +Sys.Mvc.NumberValidator.create = function Sys_Mvc_NumberValidator$create(rule) { + /// + /// + /// + return Function.createDelegate(new Sys.Mvc.NumberValidator(), new Sys.Mvc.NumberValidator().validate); +} +Sys.Mvc.NumberValidator.prototype = { + + validate: function Sys_Mvc_NumberValidator$validate(value, context) { + /// + /// + /// + /// + /// + if (Sys.Mvc._validationUtil.stringIsNullOrEmpty(value)) { + return true; + } + var n = Number.parseLocale(value); + return (!isNaN(n)); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.FormContext + +Sys.Mvc.FormContext = function Sys_Mvc_FormContext(formElement, validationSummaryElement) { + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + this._errors = []; + this.fields = new Array(0); + this._formElement = formElement; + this._validationSummaryElement = validationSummaryElement; + formElement[Sys.Mvc.FormContext._formValidationTag] = this; + if (validationSummaryElement) { + var ulElements = validationSummaryElement.getElementsByTagName('ul'); + if (ulElements.length > 0) { + this._validationSummaryULElement = ulElements[0]; + } + } + this._onClickHandler = Function.createDelegate(this, this._form_OnClick); + this._onSubmitHandler = Function.createDelegate(this, this._form_OnSubmit); +} +Sys.Mvc.FormContext._Application_Load = function Sys_Mvc_FormContext$_Application_Load() { + var allFormOptions = window.mvcClientValidationMetadata; + if (allFormOptions) { + while (allFormOptions.length > 0) { + var thisFormOptions = allFormOptions.pop(); + Sys.Mvc.FormContext._parseJsonOptions(thisFormOptions); + } + } +} +Sys.Mvc.FormContext._getFormElementsWithName = function Sys_Mvc_FormContext$_getFormElementsWithName(formElement, name) { + /// + /// + /// + /// + /// + var allElementsWithNameInForm = []; + var allElementsWithName = document.getElementsByName(name); + for (var i = 0; i < allElementsWithName.length; i++) { + var thisElement = allElementsWithName[i]; + if (Sys.Mvc.FormContext._isElementInHierarchy(formElement, thisElement)) { + Array.add(allElementsWithNameInForm, thisElement); + } + } + return allElementsWithNameInForm; +} +Sys.Mvc.FormContext.getValidationForForm = function Sys_Mvc_FormContext$getValidationForForm(formElement) { + /// + /// + /// + return formElement[Sys.Mvc.FormContext._formValidationTag]; +} +Sys.Mvc.FormContext._isElementInHierarchy = function Sys_Mvc_FormContext$_isElementInHierarchy(parent, child) { + /// + /// + /// + /// + /// + while (child) { + if (parent === child) { + return true; + } + child = child.parentNode; + } + return false; +} +Sys.Mvc.FormContext._parseJsonOptions = function Sys_Mvc_FormContext$_parseJsonOptions(options) { + /// + /// + /// + var formElement = $get(options.FormId); + var validationSummaryElement = (!Sys.Mvc._validationUtil.stringIsNullOrEmpty(options.ValidationSummaryId)) ? $get(options.ValidationSummaryId) : null; + var formContext = new Sys.Mvc.FormContext(formElement, validationSummaryElement); + formContext.enableDynamicValidation(); + formContext.replaceValidationSummary = options.ReplaceValidationSummary; + for (var i = 0; i < options.Fields.length; i++) { + var field = options.Fields[i]; + var fieldElements = Sys.Mvc.FormContext._getFormElementsWithName(formElement, field.FieldName); + var validationMessageElement = (!Sys.Mvc._validationUtil.stringIsNullOrEmpty(field.ValidationMessageId)) ? $get(field.ValidationMessageId) : null; + var fieldContext = new Sys.Mvc.FieldContext(formContext); + Array.addRange(fieldContext.elements, fieldElements); + fieldContext.validationMessageElement = validationMessageElement; + fieldContext.replaceValidationMessageContents = field.ReplaceValidationMessageContents; + for (var j = 0; j < field.ValidationRules.length; j++) { + var rule = field.ValidationRules[j]; + var validator = Sys.Mvc.ValidatorRegistry.getValidator(rule); + if (validator) { + var validation = Sys.Mvc.$create_Validation(); + validation.fieldErrorMessage = rule.ErrorMessage; + validation.validator = validator; + Array.add(fieldContext.validations, validation); + } + } + fieldContext.enableDynamicValidation(); + Array.add(formContext.fields, fieldContext); + } + var registeredValidatorCallbacks = formElement.validationCallbacks; + if (!registeredValidatorCallbacks) { + registeredValidatorCallbacks = []; + formElement.validationCallbacks = registeredValidatorCallbacks; + } + registeredValidatorCallbacks.push(Function.createDelegate(null, function() { + return Sys.Mvc._validationUtil.arrayIsNullOrEmpty(formContext.validate('submit')); + })); + return formContext; +} +Sys.Mvc.FormContext.prototype = { + _onClickHandler: null, + _onSubmitHandler: null, + _submitButtonClicked: null, + _validationSummaryElement: null, + _validationSummaryULElement: null, + _formElement: null, + replaceValidationSummary: false, + + addError: function Sys_Mvc_FormContext$addError(message) { + /// + /// + this.addErrors([ message ]); + }, + + addErrors: function Sys_Mvc_FormContext$addErrors(messages) { + /// + /// + if (!Sys.Mvc._validationUtil.arrayIsNullOrEmpty(messages)) { + Array.addRange(this._errors, messages); + this._onErrorCountChanged(); + } + }, + + clearErrors: function Sys_Mvc_FormContext$clearErrors() { + Array.clear(this._errors); + this._onErrorCountChanged(); + }, + + _displayError: function Sys_Mvc_FormContext$_displayError() { + if (this._validationSummaryElement) { + if (this._validationSummaryULElement) { + Sys.Mvc._validationUtil.removeAllChildren(this._validationSummaryULElement); + for (var i = 0; i < this._errors.length; i++) { + var liElement = document.createElement('li'); + Sys.Mvc._validationUtil.setInnerText(liElement, this._errors[i]); + this._validationSummaryULElement.appendChild(liElement); + } + } + Sys.UI.DomElement.removeCssClass(this._validationSummaryElement, Sys.Mvc.FormContext._validationSummaryValidCss); + Sys.UI.DomElement.addCssClass(this._validationSummaryElement, Sys.Mvc.FormContext._validationSummaryErrorCss); + } + }, + + _displaySuccess: function Sys_Mvc_FormContext$_displaySuccess() { + var validationSummaryElement = this._validationSummaryElement; + if (validationSummaryElement) { + var validationSummaryULElement = this._validationSummaryULElement; + if (validationSummaryULElement) { + validationSummaryULElement.innerHTML = ''; + } + Sys.UI.DomElement.removeCssClass(validationSummaryElement, Sys.Mvc.FormContext._validationSummaryErrorCss); + Sys.UI.DomElement.addCssClass(validationSummaryElement, Sys.Mvc.FormContext._validationSummaryValidCss); + } + }, + + enableDynamicValidation: function Sys_Mvc_FormContext$enableDynamicValidation() { + Sys.UI.DomEvent.addHandler(this._formElement, 'click', this._onClickHandler); + Sys.UI.DomEvent.addHandler(this._formElement, 'submit', this._onSubmitHandler); + }, + + _findSubmitButton: function Sys_Mvc_FormContext$_findSubmitButton(element) { + /// + /// + /// + if (element.disabled) { + return null; + } + var tagName = element.tagName.toUpperCase(); + var inputElement = element; + if (tagName === 'INPUT') { + var type = inputElement.type; + if (type === 'submit' || type === 'image') { + return inputElement; + } + } + else if ((tagName === 'BUTTON') && (inputElement.type === 'submit')) { + return inputElement; + } + return null; + }, + + _form_OnClick: function Sys_Mvc_FormContext$_form_OnClick(e) { + /// + /// + this._submitButtonClicked = this._findSubmitButton(e.target); + }, + + _form_OnSubmit: function Sys_Mvc_FormContext$_form_OnSubmit(e) { + /// + /// + var form = e.target; + var submitButton = this._submitButtonClicked; + if (submitButton && submitButton.disableValidation) { + return; + } + var errorMessages = this.validate('submit'); + if (!Sys.Mvc._validationUtil.arrayIsNullOrEmpty(errorMessages)) { + e.preventDefault(); + } + }, + + _onErrorCountChanged: function Sys_Mvc_FormContext$_onErrorCountChanged() { + if (!this._errors.length) { + this._displaySuccess(); + } + else { + this._displayError(); + } + }, + + validate: function Sys_Mvc_FormContext$validate(eventName) { + /// + /// + /// + var fields = this.fields; + var errors = []; + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + if (!field.elements[0].disabled) { + var thisErrors = field.validate(eventName); + if (thisErrors) { + Array.addRange(errors, thisErrors); + } + } + } + if (this.replaceValidationSummary) { + this.clearErrors(); + this.addErrors(errors); + } + return errors; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.FieldContext + +Sys.Mvc.FieldContext = function Sys_Mvc_FieldContext(formContext) { + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + this._errors = []; + this.elements = new Array(0); + this.validations = new Array(0); + this.formContext = formContext; + this._onBlurHandler = Function.createDelegate(this, this._element_OnBlur); + this._onChangeHandler = Function.createDelegate(this, this._element_OnChange); + this._onInputHandler = Function.createDelegate(this, this._element_OnInput); + this._onPropertyChangeHandler = Function.createDelegate(this, this._element_OnPropertyChange); +} +Sys.Mvc.FieldContext.prototype = { + _onBlurHandler: null, + _onChangeHandler: null, + _onInputHandler: null, + _onPropertyChangeHandler: null, + defaultErrorMessage: null, + formContext: null, + replaceValidationMessageContents: false, + validationMessageElement: null, + + addError: function Sys_Mvc_FieldContext$addError(message) { + /// + /// + this.addErrors([ message ]); + }, + + addErrors: function Sys_Mvc_FieldContext$addErrors(messages) { + /// + /// + if (!Sys.Mvc._validationUtil.arrayIsNullOrEmpty(messages)) { + Array.addRange(this._errors, messages); + this._onErrorCountChanged(); + } + }, + + clearErrors: function Sys_Mvc_FieldContext$clearErrors() { + Array.clear(this._errors); + this._onErrorCountChanged(); + }, + + _displayError: function Sys_Mvc_FieldContext$_displayError() { + var validationMessageElement = this.validationMessageElement; + if (validationMessageElement) { + if (this.replaceValidationMessageContents) { + Sys.Mvc._validationUtil.setInnerText(validationMessageElement, this._errors[0]); + } + Sys.UI.DomElement.removeCssClass(validationMessageElement, Sys.Mvc.FieldContext._validationMessageValidCss); + Sys.UI.DomElement.addCssClass(validationMessageElement, Sys.Mvc.FieldContext._validationMessageErrorCss); + } + var elements = this.elements; + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + Sys.UI.DomElement.removeCssClass(element, Sys.Mvc.FieldContext._inputElementValidCss); + Sys.UI.DomElement.addCssClass(element, Sys.Mvc.FieldContext._inputElementErrorCss); + } + }, + + _displaySuccess: function Sys_Mvc_FieldContext$_displaySuccess() { + var validationMessageElement = this.validationMessageElement; + if (validationMessageElement) { + if (this.replaceValidationMessageContents) { + Sys.Mvc._validationUtil.setInnerText(validationMessageElement, ''); + } + Sys.UI.DomElement.removeCssClass(validationMessageElement, Sys.Mvc.FieldContext._validationMessageErrorCss); + Sys.UI.DomElement.addCssClass(validationMessageElement, Sys.Mvc.FieldContext._validationMessageValidCss); + } + var elements = this.elements; + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + Sys.UI.DomElement.removeCssClass(element, Sys.Mvc.FieldContext._inputElementErrorCss); + Sys.UI.DomElement.addCssClass(element, Sys.Mvc.FieldContext._inputElementValidCss); + } + }, + + _element_OnBlur: function Sys_Mvc_FieldContext$_element_OnBlur(e) { + /// + /// + if (e.target[Sys.Mvc.FieldContext._hasTextChangedTag] || e.target[Sys.Mvc.FieldContext._hasValidationFiredTag]) { + this.validate('blur'); + } + }, + + _element_OnChange: function Sys_Mvc_FieldContext$_element_OnChange(e) { + /// + /// + e.target[Sys.Mvc.FieldContext._hasTextChangedTag] = true; + }, + + _element_OnInput: function Sys_Mvc_FieldContext$_element_OnInput(e) { + /// + /// + e.target[Sys.Mvc.FieldContext._hasTextChangedTag] = true; + if (e.target[Sys.Mvc.FieldContext._hasValidationFiredTag]) { + this.validate('input'); + } + }, + + _element_OnPropertyChange: function Sys_Mvc_FieldContext$_element_OnPropertyChange(e) { + /// + /// + if (e.rawEvent.propertyName === 'value') { + e.target[Sys.Mvc.FieldContext._hasTextChangedTag] = true; + if (e.target[Sys.Mvc.FieldContext._hasValidationFiredTag]) { + this.validate('input'); + } + } + }, + + enableDynamicValidation: function Sys_Mvc_FieldContext$enableDynamicValidation() { + var elements = this.elements; + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + if (Sys.Mvc._validationUtil.elementSupportsEvent(element, 'onpropertychange')) { + var compatMode = document.documentMode; + if (compatMode && compatMode >= 8) { + Sys.UI.DomEvent.addHandler(element, 'propertychange', this._onPropertyChangeHandler); + } + } + else { + Sys.UI.DomEvent.addHandler(element, 'input', this._onInputHandler); + } + Sys.UI.DomEvent.addHandler(element, 'change', this._onChangeHandler); + Sys.UI.DomEvent.addHandler(element, 'blur', this._onBlurHandler); + } + }, + + _getErrorString: function Sys_Mvc_FieldContext$_getErrorString(validatorReturnValue, fieldErrorMessage) { + /// + /// + /// + /// + /// + var fallbackErrorMessage = fieldErrorMessage || this.defaultErrorMessage; + if (Boolean.isInstanceOfType(validatorReturnValue)) { + return (validatorReturnValue) ? null : fallbackErrorMessage; + } + if (String.isInstanceOfType(validatorReturnValue)) { + return ((validatorReturnValue).length) ? validatorReturnValue : fallbackErrorMessage; + } + return null; + }, + + _getStringValue: function Sys_Mvc_FieldContext$_getStringValue() { + /// + var elements = this.elements; + return (elements.length > 0) ? elements[0].value : null; + }, + + _markValidationFired: function Sys_Mvc_FieldContext$_markValidationFired() { + var elements = this.elements; + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + element[Sys.Mvc.FieldContext._hasValidationFiredTag] = true; + } + }, + + _onErrorCountChanged: function Sys_Mvc_FieldContext$_onErrorCountChanged() { + if (!this._errors.length) { + this._displaySuccess(); + } + else { + this._displayError(); + } + }, + + validate: function Sys_Mvc_FieldContext$validate(eventName) { + /// + /// + /// + var validations = this.validations; + var errors = []; + var value = this._getStringValue(); + for (var i = 0; i < validations.length; i++) { + var validation = validations[i]; + var context = Sys.Mvc.$create_ValidationContext(); + context.eventName = eventName; + context.fieldContext = this; + context.validation = validation; + var retVal = validation.validator(value, context); + var errorMessage = this._getErrorString(retVal, validation.fieldErrorMessage); + if (!Sys.Mvc._validationUtil.stringIsNullOrEmpty(errorMessage)) { + Array.add(errors, errorMessage); + } + } + this._markValidationFired(); + this.clearErrors(); + this.addErrors(errors); + return errors; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.RangeValidator + +Sys.Mvc.RangeValidator = function Sys_Mvc_RangeValidator(minimum, maximum) { + /// + /// + /// + /// + /// + /// + /// + /// + this._minimum = minimum; + this._maximum = maximum; +} +Sys.Mvc.RangeValidator.create = function Sys_Mvc_RangeValidator$create(rule) { + /// + /// + /// + var min = rule.ValidationParameters['min']; + var max = rule.ValidationParameters['max']; + return Function.createDelegate(new Sys.Mvc.RangeValidator(min, max), new Sys.Mvc.RangeValidator(min, max).validate); +} +Sys.Mvc.RangeValidator.prototype = { + _minimum: null, + _maximum: null, + + validate: function Sys_Mvc_RangeValidator$validate(value, context) { + /// + /// + /// + /// + /// + if (Sys.Mvc._validationUtil.stringIsNullOrEmpty(value)) { + return true; + } + var n = Number.parseLocale(value); + return (!isNaN(n) && this._minimum <= n && n <= this._maximum); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.RegularExpressionValidator + +Sys.Mvc.RegularExpressionValidator = function Sys_Mvc_RegularExpressionValidator(pattern) { + /// + /// + /// + /// + this._pattern = pattern; +} +Sys.Mvc.RegularExpressionValidator.create = function Sys_Mvc_RegularExpressionValidator$create(rule) { + /// + /// + /// + var pattern = rule.ValidationParameters['pattern']; + return Function.createDelegate(new Sys.Mvc.RegularExpressionValidator(pattern), new Sys.Mvc.RegularExpressionValidator(pattern).validate); +} +Sys.Mvc.RegularExpressionValidator.prototype = { + _pattern: null, + + validate: function Sys_Mvc_RegularExpressionValidator$validate(value, context) { + /// + /// + /// + /// + /// + if (Sys.Mvc._validationUtil.stringIsNullOrEmpty(value)) { + return true; + } + var regExp = new RegExp(this._pattern); + var matches = regExp.exec(value); + return (!Sys.Mvc._validationUtil.arrayIsNullOrEmpty(matches) && matches[0].length === value.length); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.RequiredValidator + +Sys.Mvc.RequiredValidator = function Sys_Mvc_RequiredValidator() { +} +Sys.Mvc.RequiredValidator.create = function Sys_Mvc_RequiredValidator$create(rule) { + /// + /// + /// + return Function.createDelegate(new Sys.Mvc.RequiredValidator(), new Sys.Mvc.RequiredValidator().validate); +} +Sys.Mvc.RequiredValidator._isRadioInputElement = function Sys_Mvc_RequiredValidator$_isRadioInputElement(element) { + /// + /// + /// + if (element.tagName.toUpperCase() === 'INPUT') { + var inputType = (element.type).toUpperCase(); + if (inputType === 'RADIO') { + return true; + } + } + return false; +} +Sys.Mvc.RequiredValidator._isSelectInputElement = function Sys_Mvc_RequiredValidator$_isSelectInputElement(element) { + /// + /// + /// + if (element.tagName.toUpperCase() === 'SELECT') { + return true; + } + return false; +} +Sys.Mvc.RequiredValidator._isTextualInputElement = function Sys_Mvc_RequiredValidator$_isTextualInputElement(element) { + /// + /// + /// + if (element.tagName.toUpperCase() === 'INPUT') { + var inputType = (element.type).toUpperCase(); + switch (inputType) { + case 'TEXT': + case 'PASSWORD': + case 'FILE': + return true; + } + } + if (element.tagName.toUpperCase() === 'TEXTAREA') { + return true; + } + return false; +} +Sys.Mvc.RequiredValidator._validateRadioInput = function Sys_Mvc_RequiredValidator$_validateRadioInput(elements) { + /// + /// + /// + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + if (element.checked) { + return true; + } + } + return false; +} +Sys.Mvc.RequiredValidator._validateSelectInput = function Sys_Mvc_RequiredValidator$_validateSelectInput(optionElements) { + /// + /// + /// + for (var i = 0; i < optionElements.length; i++) { + var element = optionElements[i]; + if (element.selected) { + if (!Sys.Mvc._validationUtil.stringIsNullOrEmpty(element.value)) { + return true; + } + } + } + return false; +} +Sys.Mvc.RequiredValidator._validateTextualInput = function Sys_Mvc_RequiredValidator$_validateTextualInput(element) { + /// + /// + /// + return (!Sys.Mvc._validationUtil.stringIsNullOrEmpty(element.value)); +} +Sys.Mvc.RequiredValidator.prototype = { + + validate: function Sys_Mvc_RequiredValidator$validate(value, context) { + /// + /// + /// + /// + /// + var elements = context.fieldContext.elements; + if (!elements.length) { + return true; + } + var sampleElement = elements[0]; + if (Sys.Mvc.RequiredValidator._isTextualInputElement(sampleElement)) { + return Sys.Mvc.RequiredValidator._validateTextualInput(sampleElement); + } + if (Sys.Mvc.RequiredValidator._isRadioInputElement(sampleElement)) { + return Sys.Mvc.RequiredValidator._validateRadioInput(elements); + } + if (Sys.Mvc.RequiredValidator._isSelectInputElement(sampleElement)) { + return Sys.Mvc.RequiredValidator._validateSelectInput((sampleElement).options); + } + return true; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.StringLengthValidator + +Sys.Mvc.StringLengthValidator = function Sys_Mvc_StringLengthValidator(minLength, maxLength) { + /// + /// + /// + /// + /// + /// + /// + /// + this._minLength = minLength; + this._maxLength = maxLength; +} +Sys.Mvc.StringLengthValidator.create = function Sys_Mvc_StringLengthValidator$create(rule) { + /// + /// + /// + var minLength = (rule.ValidationParameters['min'] || 0); + var maxLength = (rule.ValidationParameters['max'] || Number.MAX_VALUE); + return Function.createDelegate(new Sys.Mvc.StringLengthValidator(minLength, maxLength), new Sys.Mvc.StringLengthValidator(minLength, maxLength).validate); +} +Sys.Mvc.StringLengthValidator.prototype = { + _maxLength: 0, + _minLength: 0, + + validate: function Sys_Mvc_StringLengthValidator$validate(value, context) { + /// + /// + /// + /// + /// + if (Sys.Mvc._validationUtil.stringIsNullOrEmpty(value)) { + return true; + } + return (this._minLength <= value.length && value.length <= this._maxLength); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc._validationUtil + +Sys.Mvc._validationUtil = function Sys_Mvc__validationUtil() { +} +Sys.Mvc._validationUtil.arrayIsNullOrEmpty = function Sys_Mvc__validationUtil$arrayIsNullOrEmpty(array) { + /// + /// + /// + return (!array || !array.length); +} +Sys.Mvc._validationUtil.stringIsNullOrEmpty = function Sys_Mvc__validationUtil$stringIsNullOrEmpty(value) { + /// + /// + /// + return (!value || !value.length); +} +Sys.Mvc._validationUtil.elementSupportsEvent = function Sys_Mvc__validationUtil$elementSupportsEvent(element, eventAttributeName) { + /// + /// + /// + /// + /// + return (eventAttributeName in element); +} +Sys.Mvc._validationUtil.removeAllChildren = function Sys_Mvc__validationUtil$removeAllChildren(element) { + /// + /// + while (element.firstChild) { + element.removeChild(element.firstChild); + } +} +Sys.Mvc._validationUtil.setInnerText = function Sys_Mvc__validationUtil$setInnerText(element, innerText) { + /// + /// + /// + /// + var textNode = document.createTextNode(innerText); + Sys.Mvc._validationUtil.removeAllChildren(element); + element.appendChild(textNode); +} + + +//////////////////////////////////////////////////////////////////////////////// +// Sys.Mvc.ValidatorRegistry + +Sys.Mvc.ValidatorRegistry = function Sys_Mvc_ValidatorRegistry() { + /// + /// +} +Sys.Mvc.ValidatorRegistry.getValidator = function Sys_Mvc_ValidatorRegistry$getValidator(rule) { + /// + /// + /// + var creator = Sys.Mvc.ValidatorRegistry.validators[rule.ValidationType]; + return (creator) ? creator(rule) : null; +} +Sys.Mvc.ValidatorRegistry._getDefaultValidators = function Sys_Mvc_ValidatorRegistry$_getDefaultValidators() { + /// + return { required: Function.createDelegate(null, Sys.Mvc.RequiredValidator.create), length: Function.createDelegate(null, Sys.Mvc.StringLengthValidator.create), regex: Function.createDelegate(null, Sys.Mvc.RegularExpressionValidator.create), range: Function.createDelegate(null, Sys.Mvc.RangeValidator.create), number: Function.createDelegate(null, Sys.Mvc.NumberValidator.create) }; +} + + +Sys.Mvc.NumberValidator.registerClass('Sys.Mvc.NumberValidator'); +Sys.Mvc.FormContext.registerClass('Sys.Mvc.FormContext'); +Sys.Mvc.FieldContext.registerClass('Sys.Mvc.FieldContext'); +Sys.Mvc.RangeValidator.registerClass('Sys.Mvc.RangeValidator'); +Sys.Mvc.RegularExpressionValidator.registerClass('Sys.Mvc.RegularExpressionValidator'); +Sys.Mvc.RequiredValidator.registerClass('Sys.Mvc.RequiredValidator'); +Sys.Mvc.StringLengthValidator.registerClass('Sys.Mvc.StringLengthValidator'); +Sys.Mvc._validationUtil.registerClass('Sys.Mvc._validationUtil'); +Sys.Mvc.ValidatorRegistry.registerClass('Sys.Mvc.ValidatorRegistry'); +Sys.Mvc.FormContext._validationSummaryErrorCss = 'validation-summary-errors'; +Sys.Mvc.FormContext._validationSummaryValidCss = 'validation-summary-valid'; +Sys.Mvc.FormContext._formValidationTag = '__MVC_FormValidation'; +Sys.Mvc.FieldContext._hasTextChangedTag = '__MVC_HasTextChanged'; +Sys.Mvc.FieldContext._hasValidationFiredTag = '__MVC_HasValidationFired'; +Sys.Mvc.FieldContext._inputElementErrorCss = 'input-validation-error'; +Sys.Mvc.FieldContext._inputElementValidCss = 'input-validation-valid'; +Sys.Mvc.FieldContext._validationMessageErrorCss = 'field-validation-error'; +Sys.Mvc.FieldContext._validationMessageValidCss = 'field-validation-valid'; +Sys.Mvc.ValidatorRegistry.validators = Sys.Mvc.ValidatorRegistry._getDefaultValidators(); + +// ---- Do not remove this footer ---- +// Generated using Script# v0.5.0.0 (http://projects.nikhilk.net) +// ----------------------------------- + +// register validation +Sys.Application.add_load(function() { + Sys.Application.remove_load(arguments.callee); + Sys.Mvc.FormContext._Application_Load(); +}); diff --git a/src/Test/Test/Scripts/MicrosoftMvcValidation.js b/src/Test/Test/Scripts/MicrosoftMvcValidation.js new file mode 100644 index 000000000..9483492f1 --- /dev/null +++ b/src/Test/Test/Scripts/MicrosoftMvcValidation.js @@ -0,0 +1,55 @@ +//---------------------------------------------------------- +// Copyright (C) Microsoft Corporation. All rights reserved. +//---------------------------------------------------------- +// MicrosoftMvcValidation.js + +Type.registerNamespace('Sys.Mvc');Sys.Mvc.$create_Validation=function(){return {};} +Sys.Mvc.$create_JsonValidationField=function(){return {};} +Sys.Mvc.$create_JsonValidationOptions=function(){return {};} +Sys.Mvc.$create_JsonValidationRule=function(){return {};} +Sys.Mvc.$create_ValidationContext=function(){return {};} +Sys.Mvc.NumberValidator=function(){} +Sys.Mvc.NumberValidator.create=function(rule){return Function.createDelegate(new Sys.Mvc.NumberValidator(),new Sys.Mvc.NumberValidator().validate);} +Sys.Mvc.NumberValidator.prototype={validate:function(value,context){if(Sys.Mvc._ValidationUtil.$1(value)){return true;}var $0=Number.parseLocale(value);return (!isNaN($0));}} +Sys.Mvc.FormContext=function(formElement,validationSummaryElement){this.$5=[];this.fields=new Array(0);this.$9=formElement;this.$7=validationSummaryElement;formElement['__MVC_FormValidation'] = this;if(validationSummaryElement){var $0=validationSummaryElement.getElementsByTagName('ul');if($0.length>0){this.$8=$0[0];}}this.$3=Function.createDelegate(this,this.$D);this.$4=Function.createDelegate(this,this.$E);} +Sys.Mvc.FormContext._Application_Load=function(){var $0=window.mvcClientValidationMetadata;if($0){while($0.length>0){var $1=$0.pop();Sys.Mvc.FormContext.$12($1);}}} +Sys.Mvc.FormContext.$F=function($p0,$p1){var $0=[];var $1=document.getElementsByName($p1);for(var $2=0;$2<$1.length;$2++){var $3=$1[$2];if(Sys.Mvc.FormContext.$10($p0,$3)){Array.add($0,$3);}}return $0;} +Sys.Mvc.FormContext.getValidationForForm=function(formElement){return formElement['__MVC_FormValidation'];} +Sys.Mvc.FormContext.$10=function($p0,$p1){while($p1){if($p0===$p1){return true;}$p1=$p1.parentNode;}return false;} +Sys.Mvc.FormContext.$12=function($p0){var $0=$get($p0.FormId);var $1=(!Sys.Mvc._ValidationUtil.$1($p0.ValidationSummaryId))?$get($p0.ValidationSummaryId):null;var $2=new Sys.Mvc.FormContext($0,$1);$2.enableDynamicValidation();$2.replaceValidationSummary=$p0.ReplaceValidationSummary;for(var $4=0;$4<$p0.Fields.length;$4++){var $5=$p0.Fields[$4];var $6=Sys.Mvc.FormContext.$F($0,$5.FieldName);var $7=(!Sys.Mvc._ValidationUtil.$1($5.ValidationMessageId))?$get($5.ValidationMessageId):null;var $8=new Sys.Mvc.FieldContext($2);Array.addRange($8.elements,$6);$8.validationMessageElement=$7;$8.replaceValidationMessageContents=$5.ReplaceValidationMessageContents;for(var $9=0;$9<$5.ValidationRules.length;$9++){var $A=$5.ValidationRules[$9];var $B=Sys.Mvc.ValidatorRegistry.getValidator($A);if($B){var $C=Sys.Mvc.$create_Validation();$C.fieldErrorMessage=$A.ErrorMessage;$C.validator=$B;Array.add($8.validations,$C);}}$8.enableDynamicValidation();Array.add($2.fields,$8);}var $3=$0.validationCallbacks;if(!$3){$3=[];$0.validationCallbacks = $3;}$3.push(Function.createDelegate(null,function(){ +return Sys.Mvc._ValidationUtil.$0($2.validate('submit'));}));return $2;} +Sys.Mvc.FormContext.prototype={$3:null,$4:null,$6:null,$7:null,$8:null,$9:null,replaceValidationSummary:false,addError:function(message){this.addErrors([message]);},addErrors:function(messages){if(!Sys.Mvc._ValidationUtil.$0(messages)){Array.addRange(this.$5,messages);this.$11();}},clearErrors:function(){Array.clear(this.$5);this.$11();},$A:function(){if(this.$7){if(this.$8){Sys.Mvc._ValidationUtil.$3(this.$8);for(var $0=0;$0=8){Sys.UI.DomEvent.addHandler($2,'propertychange',this.$9);}}else{Sys.UI.DomEvent.addHandler($2,'input',this.$8);}Sys.UI.DomEvent.addHandler($2,'change',this.$7);Sys.UI.DomEvent.addHandler($2,'blur',this.$6);}},$11:function($p0,$p1){var $0=$p1||this.defaultErrorMessage;if(Boolean.isInstanceOfType($p0)){return ($p0)?null:$0;}if(String.isInstanceOfType($p0)){return (($p0).length)?$p0:$0;}return null;},$12:function(){var $0=this.elements;return ($0.length>0)?$0[0].value:null;},$13:function(){var $0=this.elements;for(var $1=0;$1<$0.length;$1++){var $2=$0[$1];$2['__MVC_HasValidationFired'] = true;}},$14:function(){if(!this.$A.length){this.$C();}else{this.$B();}},validate:function(eventName){var $0=this.validations;var $1=[];var $2=this.$12();for(var $3=0;$3<$0.length;$3++){var $4=$0[$3];var $5=Sys.Mvc.$create_ValidationContext();$5.eventName=eventName;$5.fieldContext=this;$5.validation=$4;var $6=$4.validator($2,$5);var $7=this.$11($6,$4.fieldErrorMessage);if(!Sys.Mvc._ValidationUtil.$1($7)){Array.add($1,$7);}}this.$13();this.clearErrors();this.addErrors($1);return $1;}} +Sys.Mvc.RangeValidator=function(minimum,maximum){this.$0=minimum;this.$1=maximum;} +Sys.Mvc.RangeValidator.create=function(rule){var $0=rule.ValidationParameters['min'];var $1=rule.ValidationParameters['max'];return Function.createDelegate(new Sys.Mvc.RangeValidator($0,$1),new Sys.Mvc.RangeValidator($0,$1).validate);} +Sys.Mvc.RangeValidator.prototype={$0:null,$1:null,validate:function(value,context){if(Sys.Mvc._ValidationUtil.$1(value)){return true;}var $0=Number.parseLocale(value);return (!isNaN($0)&&this.$0<=$0&&$0<=this.$1);}} +Sys.Mvc.RegularExpressionValidator=function(pattern){this.$0=pattern;} +Sys.Mvc.RegularExpressionValidator.create=function(rule){var $0=rule.ValidationParameters['pattern'];return Function.createDelegate(new Sys.Mvc.RegularExpressionValidator($0),new Sys.Mvc.RegularExpressionValidator($0).validate);} +Sys.Mvc.RegularExpressionValidator.prototype={$0:null,validate:function(value,context){if(Sys.Mvc._ValidationUtil.$1(value)){return true;}var $0=new RegExp(this.$0);var $1=$0.exec(value);return (!Sys.Mvc._ValidationUtil.$0($1)&&$1[0].length===value.length);}} +Sys.Mvc.RequiredValidator=function(){} +Sys.Mvc.RequiredValidator.create=function(rule){return Function.createDelegate(new Sys.Mvc.RequiredValidator(),new Sys.Mvc.RequiredValidator().validate);} +Sys.Mvc.RequiredValidator.$0=function($p0){if($p0.tagName.toUpperCase()==='INPUT'){var $0=($p0.type).toUpperCase();if($0==='RADIO'){return true;}}return false;} +Sys.Mvc.RequiredValidator.$1=function($p0){if($p0.tagName.toUpperCase()==='SELECT'){return true;}return false;} +Sys.Mvc.RequiredValidator.$2=function($p0){if($p0.tagName.toUpperCase()==='INPUT'){var $0=($p0.type).toUpperCase();switch($0){case 'TEXT':case 'PASSWORD':case 'FILE':return true;}}if($p0.tagName.toUpperCase()==='TEXTAREA'){return true;}return false;} +Sys.Mvc.RequiredValidator.$3=function($p0){for(var $0=0;$0<$p0.length;$0++){var $1=$p0[$0];if($1.checked){return true;}}return false;} +Sys.Mvc.RequiredValidator.$4=function($p0){for(var $0=0;$0<$p0.length;$0++){var $1=$p0[$0];if($1.selected){if(!Sys.Mvc._ValidationUtil.$1($1.value)){return true;}}}return false;} +Sys.Mvc.RequiredValidator.$5=function($p0){return (!Sys.Mvc._ValidationUtil.$1($p0.value));} +Sys.Mvc.RequiredValidator.prototype={validate:function(value,context){var $0=context.fieldContext.elements;if(!$0.length){return true;}var $1=$0[0];if(Sys.Mvc.RequiredValidator.$2($1)){return Sys.Mvc.RequiredValidator.$5($1);}if(Sys.Mvc.RequiredValidator.$0($1)){return Sys.Mvc.RequiredValidator.$3($0);}if(Sys.Mvc.RequiredValidator.$1($1)){return Sys.Mvc.RequiredValidator.$4(($1).options);}return true;}} +Sys.Mvc.StringLengthValidator=function(minLength,maxLength){this.$1=minLength;this.$0=maxLength;} +Sys.Mvc.StringLengthValidator.create=function(rule){var $0=(rule.ValidationParameters['min']||0);var $1=(rule.ValidationParameters['max']||Number.MAX_VALUE);return Function.createDelegate(new Sys.Mvc.StringLengthValidator($0,$1),new Sys.Mvc.StringLengthValidator($0,$1).validate);} +Sys.Mvc.StringLengthValidator.prototype={$0:0,$1:0,validate:function(value,context){if(Sys.Mvc._ValidationUtil.$1(value)){return true;}return (this.$1<=value.length&&value.length<=this.$0);}} +Sys.Mvc._ValidationUtil=function(){} +Sys.Mvc._ValidationUtil.$0=function($p0){return (!$p0||!$p0.length);} +Sys.Mvc._ValidationUtil.$1=function($p0){return (!$p0||!$p0.length);} +Sys.Mvc._ValidationUtil.$2=function($p0,$p1){return ($p1 in $p0);} +Sys.Mvc._ValidationUtil.$3=function($p0){while($p0.firstChild){$p0.removeChild($p0.firstChild);}} +Sys.Mvc._ValidationUtil.$4=function($p0,$p1){var $0=document.createTextNode($p1);Sys.Mvc._ValidationUtil.$3($p0);$p0.appendChild($0);} +Sys.Mvc.ValidatorRegistry=function(){} +Sys.Mvc.ValidatorRegistry.getValidator=function(rule){var $0=Sys.Mvc.ValidatorRegistry.validators[rule.ValidationType];return ($0)?$0(rule):null;} +Sys.Mvc.ValidatorRegistry.$0=function(){return {required:Function.createDelegate(null,Sys.Mvc.RequiredValidator.create),length:Function.createDelegate(null,Sys.Mvc.StringLengthValidator.create),regex:Function.createDelegate(null,Sys.Mvc.RegularExpressionValidator.create),range:Function.createDelegate(null,Sys.Mvc.RangeValidator.create),number:Function.createDelegate(null,Sys.Mvc.NumberValidator.create)};} +Sys.Mvc.NumberValidator.registerClass('Sys.Mvc.NumberValidator');Sys.Mvc.FormContext.registerClass('Sys.Mvc.FormContext');Sys.Mvc.FieldContext.registerClass('Sys.Mvc.FieldContext');Sys.Mvc.RangeValidator.registerClass('Sys.Mvc.RangeValidator');Sys.Mvc.RegularExpressionValidator.registerClass('Sys.Mvc.RegularExpressionValidator');Sys.Mvc.RequiredValidator.registerClass('Sys.Mvc.RequiredValidator');Sys.Mvc.StringLengthValidator.registerClass('Sys.Mvc.StringLengthValidator');Sys.Mvc._ValidationUtil.registerClass('Sys.Mvc._ValidationUtil');Sys.Mvc.ValidatorRegistry.registerClass('Sys.Mvc.ValidatorRegistry');Sys.Mvc.ValidatorRegistry.validators=Sys.Mvc.ValidatorRegistry.$0(); +// ---- Do not remove this footer ---- +// Generated using Script# v0.5.0.0 (http://projects.nikhilk.net) +// ----------------------------------- +Sys.Application.add_load(function(){Sys.Application.remove_load(arguments.callee);Sys.Mvc.FormContext._Application_Load();}); \ No newline at end of file diff --git a/src/Test/Test/Scripts/jquery-1.5.1-vsdoc.js.REMOVED.git-id b/src/Test/Test/Scripts/jquery-1.5.1-vsdoc.js.REMOVED.git-id new file mode 100644 index 000000000..afb367d66 --- /dev/null +++ b/src/Test/Test/Scripts/jquery-1.5.1-vsdoc.js.REMOVED.git-id @@ -0,0 +1 @@ +8f56f29ea15515370d52a560396067bb28b52005 \ No newline at end of file diff --git a/src/Test/Test/Scripts/jquery-1.5.1.js.REMOVED.git-id b/src/Test/Test/Scripts/jquery-1.5.1.js.REMOVED.git-id new file mode 100644 index 000000000..25bdfee81 --- /dev/null +++ b/src/Test/Test/Scripts/jquery-1.5.1.js.REMOVED.git-id @@ -0,0 +1 @@ +5948d8cc4932a48bc126343cf1d5ea2ac5f0b3c0 \ No newline at end of file diff --git a/src/Test/Test/Scripts/jquery-1.5.1.min.js.REMOVED.git-id b/src/Test/Test/Scripts/jquery-1.5.1.min.js.REMOVED.git-id new file mode 100644 index 000000000..1013447da --- /dev/null +++ b/src/Test/Test/Scripts/jquery-1.5.1.min.js.REMOVED.git-id @@ -0,0 +1 @@ +eec584bc589cf1ab1fe50781c1780f89c90aa31b \ No newline at end of file diff --git a/src/Test/Test/Scripts/jquery-ui-1.8.11.js.REMOVED.git-id b/src/Test/Test/Scripts/jquery-ui-1.8.11.js.REMOVED.git-id new file mode 100644 index 000000000..281a68518 --- /dev/null +++ b/src/Test/Test/Scripts/jquery-ui-1.8.11.js.REMOVED.git-id @@ -0,0 +1 @@ +79285779228262f9c021d1ee5a455c6f7f4c1113 \ No newline at end of file diff --git a/src/Test/Test/Scripts/jquery-ui-1.8.11.min.js.REMOVED.git-id b/src/Test/Test/Scripts/jquery-ui-1.8.11.min.js.REMOVED.git-id new file mode 100644 index 000000000..ec266dd80 --- /dev/null +++ b/src/Test/Test/Scripts/jquery-ui-1.8.11.min.js.REMOVED.git-id @@ -0,0 +1 @@ +89ff61bcba0fbfbe359c0d3734942d260b702a4b \ No newline at end of file diff --git a/src/Test/Test/Scripts/jquery.unobtrusive-ajax.js b/src/Test/Test/Scripts/jquery.unobtrusive-ajax.js new file mode 100644 index 000000000..95cdfd331 --- /dev/null +++ b/src/Test/Test/Scripts/jquery.unobtrusive-ajax.js @@ -0,0 +1,165 @@ +/// + +/*! +** Unobtrusive Ajax support library for jQuery +** Copyright (C) Microsoft Corporation. All rights reserved. +*/ + +/*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 */ +/*global window: false, jQuery: false */ + +(function ($) { + var data_click = "unobtrusiveAjaxClick", + data_validation = "unobtrusiveValidation"; + + function getFunction(code, argNames) { + var fn = window, parts = (code || "").split("."); + while (fn && parts.length) { + fn = fn[parts.shift()]; + } + if (typeof (fn) === "function") { + return fn; + } + argNames.push(code); + return Function.constructor.apply(null, argNames); + } + + function isMethodProxySafe(method) { + return method === "GET" || method === "POST"; + } + + function asyncOnBeforeSend(xhr, method) { + if (!isMethodProxySafe(method)) { + xhr.setRequestHeader("X-HTTP-Method-Override", method); + } + } + + function asyncOnSuccess(element, data, contentType) { + var mode; + + if (contentType.indexOf("application/x-javascript") !== -1) { // jQuery already executes JavaScript for us + return; + } + + mode = (element.getAttribute("data-ajax-mode") || "").toUpperCase(); + $(element.getAttribute("data-ajax-update")).each(function (i, update) { + var top; + + switch (mode) { + case "BEFORE": + top = update.firstChild; + $("
").html(data).contents().each(function () { + update.insertBefore(this, top); + }); + break; + case "AFTER": + $("
").html(data).contents().each(function () { + update.appendChild(this); + }); + break; + default: + $(update).html(data); + break; + } + }); + } + + function asyncRequest(element, options) { + var confirm, loading, method, duration; + + confirm = element.getAttribute("data-ajax-confirm"); + if (confirm && !window.confirm(confirm)) { + return; + } + + loading = $(element.getAttribute("data-ajax-loading")); + duration = element.getAttribute("data-ajax-loading-duration") || 0; + + $.extend(options, { + type: element.getAttribute("data-ajax-method") || undefined, + url: element.getAttribute("data-ajax-url") || undefined, + beforeSend: function (xhr) { + var result; + asyncOnBeforeSend(xhr, method); + result = getFunction(element.getAttribute("data-ajax-begin"), ["xhr"]).apply(this, arguments); + if (result !== false) { + loading.show(duration); + } + return result; + }, + complete: function () { + loading.hide(duration); + getFunction(element.getAttribute("data-ajax-complete"), ["xhr", "status"]).apply(this, arguments); + }, + success: function (data, status, xhr) { + asyncOnSuccess(element, data, xhr.getResponseHeader("Content-Type") || "text/html"); + getFunction(element.getAttribute("data-ajax-success"), ["data", "status", "xhr"]).apply(this, arguments); + }, + error: getFunction(element.getAttribute("data-ajax-failure"), ["xhr", "status", "error"]) + }); + + options.data.push({ name: "X-Requested-With", value: "XMLHttpRequest" }); + + method = options.type.toUpperCase(); + if (!isMethodProxySafe(method)) { + options.type = "POST"; + options.data.push({ name: "X-HTTP-Method-Override", value: method }); + } + + $.ajax(options); + } + + function validate(form) { + var validationInfo = $(form).data(data_validation); + return !validationInfo || !validationInfo.validate || validationInfo.validate(); + } + + $("a[data-ajax=true]").live("click", function (evt) { + evt.preventDefault(); + asyncRequest(this, { + url: this.href, + type: "GET", + data: [] + }); + }); + + $("form[data-ajax=true] input[type=image]").live("click", function (evt) { + var name = evt.target.name, + $target = $(evt.target), + form = $target.parents("form")[0], + offset = $target.offset(); + + $(form).data(data_click, [ + { name: name + ".x", value: Math.round(evt.pageX - offset.left) }, + { name: name + ".y", value: Math.round(evt.pageY - offset.top) } + ]); + + setTimeout(function () { + $(form).removeData(data_click); + }, 0); + }); + + $("form[data-ajax=true] :submit").live("click", function (evt) { + var name = evt.target.name, + form = $(evt.target).parents("form")[0]; + + $(form).data(data_click, name ? [{ name: name, value: evt.target.value }] : []); + + setTimeout(function () { + $(form).removeData(data_click); + }, 0); + }); + + $("form[data-ajax=true]").live("submit", function (evt) { + var clickInfo = $(this).data(data_click) || []; + evt.preventDefault(); + if (!validate(this)) { + return; + } + asyncRequest(this, { + url: this.action, + type: this.method || "GET", + data: clickInfo.concat($(this).serializeArray()) + }); + }); +}(jQuery)); \ No newline at end of file diff --git a/src/Test/Test/Scripts/jquery.unobtrusive-ajax.min.js b/src/Test/Test/Scripts/jquery.unobtrusive-ajax.min.js new file mode 100644 index 000000000..3542991c1 --- /dev/null +++ b/src/Test/Test/Scripts/jquery.unobtrusive-ajax.min.js @@ -0,0 +1,5 @@ +/* +** Unobtrusive Ajax support library for jQuery +** Copyright (C) Microsoft Corporation. All rights reserved. +*/ +(function(a){var b="unobtrusiveAjaxClick",g="unobtrusiveValidation";function c(d,b){var a=window,c=(d||"").split(".");while(a&&c.length)a=a[c.shift()];if(typeof a==="function")return a;b.push(d);return Function.constructor.apply(null,b)}function d(a){return a==="GET"||a==="POST"}function f(b,a){!d(a)&&b.setRequestHeader("X-HTTP-Method-Override",a)}function h(c,b,e){var d;if(e.indexOf("application/x-javascript")!==-1)return;d=(c.getAttribute("data-ajax-mode")||"").toUpperCase();a(c.getAttribute("data-ajax-update")).each(function(f,c){var e;switch(d){case"BEFORE":e=c.firstChild;a("
").html(b).contents().each(function(){c.insertBefore(this,e)});break;case"AFTER":a("
").html(b).contents().each(function(){c.appendChild(this)});break;default:a(c).html(b)}})}function e(b,e){var j,k,g,i;j=b.getAttribute("data-ajax-confirm");if(j&&!window.confirm(j))return;k=a(b.getAttribute("data-ajax-loading"));i=b.getAttribute("data-ajax-loading-duration")||0;a.extend(e,{type:b.getAttribute("data-ajax-method")||undefined,url:b.getAttribute("data-ajax-url")||undefined,beforeSend:function(d){var a;f(d,g);a=c(b.getAttribute("data-ajax-begin"),["xhr"]).apply(this,arguments);a!==false&&k.show(i);return a},complete:function(){k.hide(i);c(b.getAttribute("data-ajax-complete"),["xhr","status"]).apply(this,arguments)},success:function(a,e,d){h(b,a,d.getResponseHeader("Content-Type")||"text/html");c(b.getAttribute("data-ajax-success"),["data","status","xhr"]).apply(this,arguments)},error:c(b.getAttribute("data-ajax-failure"),["xhr","status","error"])});e.data.push({name:"X-Requested-With",value:"XMLHttpRequest"});g=e.type.toUpperCase();if(!d(g)){e.type="POST";e.data.push({name:"X-HTTP-Method-Override",value:g})}a.ajax(e)}function i(c){var b=a(c).data(g);return!b||!b.validate||b.validate()}a("a[data-ajax=true]").live("click",function(a){a.preventDefault();e(this,{url:this.href,type:"GET",data:[]})});a("form[data-ajax=true] input[type=image]").live("click",function(c){var g=c.target.name,d=a(c.target),f=d.parents("form")[0],e=d.offset();a(f).data(b,[{name:g+".x",value:Math.round(c.pageX-e.left)},{name:g+".y",value:Math.round(c.pageY-e.top)}]);setTimeout(function(){a(f).removeData(b)},0)});a("form[data-ajax=true] :submit").live("click",function(c){var e=c.target.name,d=a(c.target).parents("form")[0];a(d).data(b,e?[{name:e,value:c.target.value}]:[]);setTimeout(function(){a(d).removeData(b)},0)});a("form[data-ajax=true]").live("submit",function(d){var c=a(this).data(b)||[];d.preventDefault();if(!i(this))return;e(this,{url:this.action,type:this.method||"GET",data:c.concat(a(this).serializeArray())})})})(jQuery); \ No newline at end of file diff --git a/src/Test/Test/Scripts/jquery.validate-vsdoc.js b/src/Test/Test/Scripts/jquery.validate-vsdoc.js new file mode 100644 index 000000000..30774ac11 --- /dev/null +++ b/src/Test/Test/Scripts/jquery.validate-vsdoc.js @@ -0,0 +1,1299 @@ +/* +* This file has been commented to support Visual Studio Intellisense. +* You should not use this file at runtime inside the browser--it is only +* intended to be used only for design-time IntelliSense. Please use the +* standard jQuery library for all production use. +* +* Comment version: 1.8 +*/ + +/* +* Note: While Microsoft is not the author of this file, Microsoft is +* offering you a license subject to the terms of the Microsoft Software +* License Terms for Microsoft ASP.NET Model View Controller 3. +* Microsoft reserves all other rights. The notices below are provided +* for informational purposes only and are not the license terms under +* which Microsoft distributed this file. +* +* jQuery validation plugin 1.8.0 +* +* http://bassistance.de/jquery-plugins/jquery-plugin-validation/ +* http://docs.jquery.com/Plugins/Validation +* +* Copyright (c) 2006 - 2011 Jörn Zaefferer +* +*/ + +(function($) { + +$.extend($.fn, { + // http://docs.jquery.com/Plugins/Validation/validate + validate: function( options ) { + /// + /// Validates the selected form. This method sets up event handlers for submit, focus, + /// keyup, blur and click to trigger validation of the entire form or individual + /// elements. Each one can be disabled, see the onxxx options (onsubmit, onfocusout, + /// onkeyup, onclick). focusInvalid focuses elements when submitting a invalid form. + /// + /// + /// A set of key/value pairs that configure the validate. All options are optional. + /// + /// + + // if nothing is selected, return nothing; can't chain anyway + if (!this.length) { + options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" ); + return; + } + + // check if a validator for this form was already created + var validator = $.data(this[0], 'validator'); + if ( validator ) { + return validator; + } + + validator = new $.validator( options, this[0] ); + $.data(this[0], 'validator', validator); + + if ( validator.settings.onsubmit ) { + + // allow suppresing validation by adding a cancel class to the submit button + this.find("input, button").filter(".cancel").click(function() { + validator.cancelSubmit = true; + }); + + // when a submitHandler is used, capture the submitting button + if (validator.settings.submitHandler) { + this.find("input, button").filter(":submit").click(function() { + validator.submitButton = this; + }); + } + + // validate the form on submit + this.submit( function( event ) { + if ( validator.settings.debug ) + // prevent form submit to be able to see console output + event.preventDefault(); + + function handle() { + if ( validator.settings.submitHandler ) { + if (validator.submitButton) { + // insert a hidden input as a replacement for the missing submit button + var hidden = $("").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm); + } + validator.settings.submitHandler.call( validator, validator.currentForm ); + if (validator.submitButton) { + // and clean up afterwards; thanks to no-block-scope, hidden can be referenced + hidden.remove(); + } + return false; + } + return true; + } + + // prevent submit for invalid forms or custom submit handlers + if ( validator.cancelSubmit ) { + validator.cancelSubmit = false; + return handle(); + } + if ( validator.form() ) { + if ( validator.pendingRequest ) { + validator.formSubmitted = true; + return false; + } + return handle(); + } else { + validator.focusInvalid(); + return false; + } + }); + } + + return validator; + }, + // http://docs.jquery.com/Plugins/Validation/valid + valid: function() { + /// + /// Checks if the selected form is valid or if all selected elements are valid. + /// validate() needs to be called on the form before checking it using this method. + /// + /// + + if ( $(this[0]).is('form')) { + return this.validate().form(); + } else { + var valid = true; + var validator = $(this[0].form).validate(); + this.each(function() { + valid &= validator.element(this); + }); + return valid; + } + }, + // attributes: space seperated list of attributes to retrieve and remove + removeAttrs: function(attributes) { + /// + /// Remove the specified attributes from the first matched element and return them. + /// + /// + /// A space-seperated list of attribute names to remove. + /// + /// + + var result = {}, + $element = this; + $.each(attributes.split(/\s/), function(index, value) { + result[value] = $element.attr(value); + $element.removeAttr(value); + }); + return result; + }, + // http://docs.jquery.com/Plugins/Validation/rules + rules: function(command, argument) { + /// + /// Return the validations rules for the first selected element. + /// + /// + /// Can be either "add" or "remove". + /// + /// + /// A list of rules to add or remove. + /// + /// + + var element = this[0]; + + if (command) { + var settings = $.data(element.form, 'validator').settings; + var staticRules = settings.rules; + var existingRules = $.validator.staticRules(element); + switch(command) { + case "add": + $.extend(existingRules, $.validator.normalizeRule(argument)); + staticRules[element.name] = existingRules; + if (argument.messages) + settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages ); + break; + case "remove": + if (!argument) { + delete staticRules[element.name]; + return existingRules; + } + var filtered = {}; + $.each(argument.split(/\s/), function(index, method) { + filtered[method] = existingRules[method]; + delete existingRules[method]; + }); + return filtered; + } + } + + var data = $.validator.normalizeRules( + $.extend( + {}, + $.validator.metadataRules(element), + $.validator.classRules(element), + $.validator.attributeRules(element), + $.validator.staticRules(element) + ), element); + + // make sure required is at front + if (data.required) { + var param = data.required; + delete data.required; + data = $.extend({required: param}, data); + } + + return data; + } +}); + +// Custom selectors +$.extend($.expr[":"], { + // http://docs.jquery.com/Plugins/Validation/blank + blank: function(a) {return !$.trim("" + a.value);}, + // http://docs.jquery.com/Plugins/Validation/filled + filled: function(a) {return !!$.trim("" + a.value);}, + // http://docs.jquery.com/Plugins/Validation/unchecked + unchecked: function(a) {return !a.checked;} +}); + +// constructor for validator +$.validator = function( options, form ) { + this.settings = $.extend( true, {}, $.validator.defaults, options ); + this.currentForm = form; + this.init(); +}; + +$.validator.format = function(source, params) { + /// + /// Replaces {n} placeholders with arguments. + /// One or more arguments can be passed, in addition to the string template itself, to insert + /// into the string. + /// + /// + /// The string to format. + /// + /// + /// The first argument to insert, or an array of Strings to insert + /// + /// + + if ( arguments.length == 1 ) + return function() { + var args = $.makeArray(arguments); + args.unshift(source); + return $.validator.format.apply( this, args ); + }; + if ( arguments.length > 2 && params.constructor != Array ) { + params = $.makeArray(arguments).slice(1); + } + if ( params.constructor != Array ) { + params = [ params ]; + } + $.each(params, function(i, n) { + source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n); + }); + return source; +}; + +$.extend($.validator, { + + defaults: { + messages: {}, + groups: {}, + rules: {}, + errorClass: "error", + validClass: "valid", + errorElement: "label", + focusInvalid: true, + errorContainer: $( [] ), + errorLabelContainer: $( [] ), + onsubmit: true, + ignore: [], + ignoreTitle: false, + onfocusin: function(element) { + this.lastActive = element; + + // hide error label and remove error class on focus if enabled + if ( this.settings.focusCleanup && !this.blockFocusCleanup ) { + this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass ); + this.addWrapper(this.errorsFor(element)).hide(); + } + }, + onfocusout: function(element) { + if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) { + this.element(element); + } + }, + onkeyup: function(element) { + if ( element.name in this.submitted || element == this.lastElement ) { + this.element(element); + } + }, + onclick: function(element) { + // click on selects, radiobuttons and checkboxes + if ( element.name in this.submitted ) + this.element(element); + // or option elements, check parent select in that case + else if (element.parentNode.name in this.submitted) + this.element(element.parentNode); + }, + highlight: function( element, errorClass, validClass ) { + $(element).addClass(errorClass).removeClass(validClass); + }, + unhighlight: function( element, errorClass, validClass ) { + $(element).removeClass(errorClass).addClass(validClass); + } + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults + setDefaults: function(settings) { + /// + /// Modify default settings for validation. + /// Accepts everything that Plugins/Validation/validate accepts. + /// + /// + /// Options to set as default. + /// + /// + + $.extend( $.validator.defaults, settings ); + }, + + messages: { + required: "This field is required.", + remote: "Please fix this field.", + email: "Please enter a valid email address.", + url: "Please enter a valid URL.", + date: "Please enter a valid date.", + dateISO: "Please enter a valid date (ISO).", + number: "Please enter a valid number.", + digits: "Please enter only digits.", + creditcard: "Please enter a valid credit card number.", + equalTo: "Please enter the same value again.", + accept: "Please enter a value with a valid extension.", + maxlength: $.validator.format("Please enter no more than {0} characters."), + minlength: $.validator.format("Please enter at least {0} characters."), + rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."), + range: $.validator.format("Please enter a value between {0} and {1}."), + max: $.validator.format("Please enter a value less than or equal to {0}."), + min: $.validator.format("Please enter a value greater than or equal to {0}.") + }, + + autoCreateRanges: false, + + prototype: { + + init: function() { + this.labelContainer = $(this.settings.errorLabelContainer); + this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm); + this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer ); + this.submitted = {}; + this.valueCache = {}; + this.pendingRequest = 0; + this.pending = {}; + this.invalid = {}; + this.reset(); + + var groups = (this.groups = {}); + $.each(this.settings.groups, function(key, value) { + $.each(value.split(/\s/), function(index, name) { + groups[name] = key; + }); + }); + var rules = this.settings.rules; + $.each(rules, function(key, value) { + rules[key] = $.validator.normalizeRule(value); + }); + + function delegate(event) { + var validator = $.data(this[0].form, "validator"), + eventType = "on" + event.type.replace(/^validate/, ""); + validator.settings[eventType] && validator.settings[eventType].call(validator, this[0] ); + } + $(this.currentForm) + .validateDelegate(":text, :password, :file, select, textarea", "focusin focusout keyup", delegate) + .validateDelegate(":radio, :checkbox, select, option", "click", delegate); + + if (this.settings.invalidHandler) + $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler); + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/form + form: function() { + /// + /// Validates the form, returns true if it is valid, false otherwise. + /// This behaves as a normal submit event, but returns the result. + /// + /// + + this.checkForm(); + $.extend(this.submitted, this.errorMap); + this.invalid = $.extend({}, this.errorMap); + if (!this.valid()) + $(this.currentForm).triggerHandler("invalid-form", [this]); + this.showErrors(); + return this.valid(); + }, + + checkForm: function() { + this.prepareForm(); + for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) { + this.check( elements[i] ); + } + return this.valid(); + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/element + element: function( element ) { + /// + /// Validates a single element, returns true if it is valid, false otherwise. + /// This behaves as validation on blur or keyup, but returns the result. + /// + /// + /// An element to validate, must be inside the validated form. + /// + /// + + element = this.clean( element ); + this.lastElement = element; + this.prepareElement( element ); + this.currentElements = $(element); + var result = this.check( element ); + if ( result ) { + delete this.invalid[element.name]; + } else { + this.invalid[element.name] = true; + } + if ( !this.numberOfInvalids() ) { + // Hide error containers on last error + this.toHide = this.toHide.add( this.containers ); + } + this.showErrors(); + return result; + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/showErrors + showErrors: function(errors) { + /// + /// Show the specified messages. + /// Keys have to refer to the names of elements, values are displayed for those elements, using the configured error placement. + /// + /// + /// One or more key/value pairs of input names and messages. + /// + /// + + if(errors) { + // add items to error list and map + $.extend( this.errorMap, errors ); + this.errorList = []; + for ( var name in errors ) { + this.errorList.push({ + message: errors[name], + element: this.findByName(name)[0] + }); + } + // remove items from success list + this.successList = $.grep( this.successList, function(element) { + return !(element.name in errors); + }); + } + this.settings.showErrors + ? this.settings.showErrors.call( this, this.errorMap, this.errorList ) + : this.defaultShowErrors(); + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/resetForm + resetForm: function() { + /// + /// Resets the controlled form. + /// Resets input fields to their original value (requires form plugin), removes classes + /// indicating invalid elements and hides error messages. + /// + /// + + if ( $.fn.resetForm ) + $( this.currentForm ).resetForm(); + this.submitted = {}; + this.prepareForm(); + this.hideErrors(); + this.elements().removeClass( this.settings.errorClass ); + }, + + numberOfInvalids: function() { + /// + /// Returns the number of invalid fields. + /// This depends on the internal validator state. It covers all fields only after + /// validating the complete form (on submit or via $("form").valid()). After validating + /// a single element, only that element is counted. Most useful in combination with the + /// invalidHandler-option. + /// + /// + + return this.objectLength(this.invalid); + }, + + objectLength: function( obj ) { + var count = 0; + for ( var i in obj ) + count++; + return count; + }, + + hideErrors: function() { + this.addWrapper( this.toHide ).hide(); + }, + + valid: function() { + return this.size() == 0; + }, + + size: function() { + return this.errorList.length; + }, + + focusInvalid: function() { + if( this.settings.focusInvalid ) { + try { + $(this.findLastActive() || this.errorList.length && this.errorList[0].element || []) + .filter(":visible") + .focus() + // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find + .trigger("focusin"); + } catch(e) { + // ignore IE throwing errors when focusing hidden elements + } + } + }, + + findLastActive: function() { + var lastActive = this.lastActive; + return lastActive && $.grep(this.errorList, function(n) { + return n.element.name == lastActive.name; + }).length == 1 && lastActive; + }, + + elements: function() { + var validator = this, + rulesCache = {}; + + // select all valid inputs inside the form (no submit or reset buttons) + // workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved + return $([]).add(this.currentForm.elements) + .filter(":input") + .not(":submit, :reset, :image, [disabled]") + .not( this.settings.ignore ) + .filter(function() { + !this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this); + + // select only the first element for each name, and only those with rules specified + if ( this.name in rulesCache || !validator.objectLength($(this).rules()) ) + return false; + + rulesCache[this.name] = true; + return true; + }); + }, + + clean: function( selector ) { + return $( selector )[0]; + }, + + errors: function() { + return $( this.settings.errorElement + "." + this.settings.errorClass, this.errorContext ); + }, + + reset: function() { + this.successList = []; + this.errorList = []; + this.errorMap = {}; + this.toShow = $([]); + this.toHide = $([]); + this.currentElements = $([]); + }, + + prepareForm: function() { + this.reset(); + this.toHide = this.errors().add( this.containers ); + }, + + prepareElement: function( element ) { + this.reset(); + this.toHide = this.errorsFor(element); + }, + + check: function( element ) { + element = this.clean( element ); + + // if radio/checkbox, validate first element in group instead + if (this.checkable(element)) { + element = this.findByName(element.name).not(this.settings.ignore)[0]; + } + + var rules = $(element).rules(); + var dependencyMismatch = false; + for (var method in rules) { + var rule = { method: method, parameters: rules[method] }; + try { + var result = $.validator.methods[method].call( this, element.value.replace(/\r/g, ""), element, rule.parameters ); + + // if a method indicates that the field is optional and therefore valid, + // don't mark it as valid when there are no other rules + if ( result == "dependency-mismatch" ) { + dependencyMismatch = true; + continue; + } + dependencyMismatch = false; + + if ( result == "pending" ) { + this.toHide = this.toHide.not( this.errorsFor(element) ); + return; + } + + if( !result ) { + this.formatAndAdd( element, rule ); + return false; + } + } catch(e) { + this.settings.debug && window.console && console.log("exception occured when checking element " + element.id + + ", check the '" + rule.method + "' method", e); + throw e; + } + } + if (dependencyMismatch) + return; + if ( this.objectLength(rules) ) + this.successList.push(element); + return true; + }, + + // return the custom message for the given element and validation method + // specified in the element's "messages" metadata + customMetaMessage: function(element, method) { + if (!$.metadata) + return; + + var meta = this.settings.meta + ? $(element).metadata()[this.settings.meta] + : $(element).metadata(); + + return meta && meta.messages && meta.messages[method]; + }, + + // return the custom message for the given element name and validation method + customMessage: function( name, method ) { + var m = this.settings.messages[name]; + return m && (m.constructor == String + ? m + : m[method]); + }, + + // return the first defined argument, allowing empty strings + findDefined: function() { + for(var i = 0; i < arguments.length; i++) { + if (arguments[i] !== undefined) + return arguments[i]; + } + return undefined; + }, + + defaultMessage: function( element, method) { + return this.findDefined( + this.customMessage( element.name, method ), + this.customMetaMessage( element, method ), + // title is never undefined, so handle empty string as undefined + !this.settings.ignoreTitle && element.title || undefined, + $.validator.messages[method], + "Warning: No message defined for " + element.name + "" + ); + }, + + formatAndAdd: function( element, rule ) { + var message = this.defaultMessage( element, rule.method ), + theregex = /\$?\{(\d+)\}/g; + if ( typeof message == "function" ) { + message = message.call(this, rule.parameters, element); + } else if (theregex.test(message)) { + message = jQuery.format(message.replace(theregex, '{$1}'), rule.parameters); + } + this.errorList.push({ + message: message, + element: element + }); + + this.errorMap[element.name] = message; + this.submitted[element.name] = message; + }, + + addWrapper: function(toToggle) { + if ( this.settings.wrapper ) + toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) ); + return toToggle; + }, + + defaultShowErrors: function() { + for ( var i = 0; this.errorList[i]; i++ ) { + var error = this.errorList[i]; + this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass ); + this.showLabel( error.element, error.message ); + } + if( this.errorList.length ) { + this.toShow = this.toShow.add( this.containers ); + } + if (this.settings.success) { + for ( var i = 0; this.successList[i]; i++ ) { + this.showLabel( this.successList[i] ); + } + } + if (this.settings.unhighlight) { + for ( var i = 0, elements = this.validElements(); elements[i]; i++ ) { + this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass ); + } + } + this.toHide = this.toHide.not( this.toShow ); + this.hideErrors(); + this.addWrapper( this.toShow ).show(); + }, + + validElements: function() { + return this.currentElements.not(this.invalidElements()); + }, + + invalidElements: function() { + return $(this.errorList).map(function() { + return this.element; + }); + }, + + showLabel: function(element, message) { + var label = this.errorsFor( element ); + if ( label.length ) { + // refresh error/success class + label.removeClass().addClass( this.settings.errorClass ); + + // check if we have a generated label, replace the message then + label.attr("generated") && label.html(message); + } else { + // create label + label = $("<" + this.settings.errorElement + "/>") + .attr({"for": this.idOrName(element), generated: true}) + .addClass(this.settings.errorClass) + .html(message || ""); + if ( this.settings.wrapper ) { + // make sure the element is visible, even in IE + // actually showing the wrapped element is handled elsewhere + label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent(); + } + if ( !this.labelContainer.append(label).length ) + this.settings.errorPlacement + ? this.settings.errorPlacement(label, $(element) ) + : label.insertAfter(element); + } + if ( !message && this.settings.success ) { + label.text(""); + typeof this.settings.success == "string" + ? label.addClass( this.settings.success ) + : this.settings.success( label ); + } + this.toShow = this.toShow.add(label); + }, + + errorsFor: function(element) { + var name = this.idOrName(element); + return this.errors().filter(function() { + return $(this).attr('for') == name; + }); + }, + + idOrName: function(element) { + return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name); + }, + + checkable: function( element ) { + return /radio|checkbox/i.test(element.type); + }, + + findByName: function( name ) { + // select by name and filter by form for performance over form.find("[name=...]") + var form = this.currentForm; + return $(document.getElementsByName(name)).map(function(index, element) { + return element.form == form && element.name == name && element || null; + }); + }, + + getLength: function(value, element) { + switch( element.nodeName.toLowerCase() ) { + case 'select': + return $("option:selected", element).length; + case 'input': + if( this.checkable( element) ) + return this.findByName(element.name).filter(':checked').length; + } + return value.length; + }, + + depend: function(param, element) { + return this.dependTypes[typeof param] + ? this.dependTypes[typeof param](param, element) + : true; + }, + + dependTypes: { + "boolean": function(param, element) { + return param; + }, + "string": function(param, element) { + return !!$(param, element.form).length; + }, + "function": function(param, element) { + return param(element); + } + }, + + optional: function(element) { + return !$.validator.methods.required.call(this, $.trim(element.value), element) && "dependency-mismatch"; + }, + + startRequest: function(element) { + if (!this.pending[element.name]) { + this.pendingRequest++; + this.pending[element.name] = true; + } + }, + + stopRequest: function(element, valid) { + this.pendingRequest--; + // sometimes synchronization fails, make sure pendingRequest is never < 0 + if (this.pendingRequest < 0) + this.pendingRequest = 0; + delete this.pending[element.name]; + if ( valid && this.pendingRequest == 0 && this.formSubmitted && this.form() ) { + $(this.currentForm).submit(); + this.formSubmitted = false; + } else if (!valid && this.pendingRequest == 0 && this.formSubmitted) { + $(this.currentForm).triggerHandler("invalid-form", [this]); + this.formSubmitted = false; + } + }, + + previousValue: function(element) { + return $.data(element, "previousValue") || $.data(element, "previousValue", { + old: null, + valid: true, + message: this.defaultMessage( element, "remote" ) + }); + } + + }, + + classRuleSettings: { + required: {required: true}, + email: {email: true}, + url: {url: true}, + date: {date: true}, + dateISO: {dateISO: true}, + dateDE: {dateDE: true}, + number: {number: true}, + numberDE: {numberDE: true}, + digits: {digits: true}, + creditcard: {creditcard: true} + }, + + addClassRules: function(className, rules) { + /// + /// Add a compound class method - useful to refactor common combinations of rules into a single + /// class. + /// + /// + /// The name of the class rule to add + /// + /// + /// The compound rules + /// + /// + + className.constructor == String ? + this.classRuleSettings[className] = rules : + $.extend(this.classRuleSettings, className); + }, + + classRules: function(element) { + var rules = {}; + var classes = $(element).attr('class'); + classes && $.each(classes.split(' '), function() { + if (this in $.validator.classRuleSettings) { + $.extend(rules, $.validator.classRuleSettings[this]); + } + }); + return rules; + }, + + attributeRules: function(element) { + var rules = {}; + var $element = $(element); + + for (var method in $.validator.methods) { + var value = $element.attr(method); + if (value) { + rules[method] = value; + } + } + + // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs + if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) { + delete rules.maxlength; + } + + return rules; + }, + + metadataRules: function(element) { + if (!$.metadata) return {}; + + var meta = $.data(element.form, 'validator').settings.meta; + return meta ? + $(element).metadata()[meta] : + $(element).metadata(); + }, + + staticRules: function(element) { + var rules = {}; + var validator = $.data(element.form, 'validator'); + if (validator.settings.rules) { + rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {}; + } + return rules; + }, + + normalizeRules: function(rules, element) { + // handle dependency check + $.each(rules, function(prop, val) { + // ignore rule when param is explicitly false, eg. required:false + if (val === false) { + delete rules[prop]; + return; + } + if (val.param || val.depends) { + var keepRule = true; + switch (typeof val.depends) { + case "string": + keepRule = !!$(val.depends, element.form).length; + break; + case "function": + keepRule = val.depends.call(element, element); + break; + } + if (keepRule) { + rules[prop] = val.param !== undefined ? val.param : true; + } else { + delete rules[prop]; + } + } + }); + + // evaluate parameters + $.each(rules, function(rule, parameter) { + rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter; + }); + + // clean number parameters + $.each(['minlength', 'maxlength', 'min', 'max'], function() { + if (rules[this]) { + rules[this] = Number(rules[this]); + } + }); + $.each(['rangelength', 'range'], function() { + if (rules[this]) { + rules[this] = [Number(rules[this][0]), Number(rules[this][1])]; + } + }); + + if ($.validator.autoCreateRanges) { + // auto-create ranges + if (rules.min && rules.max) { + rules.range = [rules.min, rules.max]; + delete rules.min; + delete rules.max; + } + if (rules.minlength && rules.maxlength) { + rules.rangelength = [rules.minlength, rules.maxlength]; + delete rules.minlength; + delete rules.maxlength; + } + } + + // To support custom messages in metadata ignore rule methods titled "messages" + if (rules.messages) { + delete rules.messages; + } + + return rules; + }, + + // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true} + normalizeRule: function(data) { + if( typeof data == "string" ) { + var transformed = {}; + $.each(data.split(/\s/), function() { + transformed[this] = true; + }); + data = transformed; + } + return data; + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/addMethod + addMethod: function(name, method, message) { + /// + /// Add a custom validation method. It must consist of a name (must be a legal javascript + /// identifier), a javascript based function and a default string message. + /// + /// + /// The name of the method, used to identify and referencing it, must be a valid javascript + /// identifier + /// + /// + /// The actual method implementation, returning true if an element is valid + /// + /// + /// (Optional) The default message to display for this method. Can be a function created by + /// jQuery.validator.format(value). When undefined, an already existing message is used + /// (handy for localization), otherwise the field-specific messages have to be defined. + /// + /// + + $.validator.methods[name] = method; + $.validator.messages[name] = message != undefined ? message : $.validator.messages[name]; + if (method.length < 3) { + $.validator.addClassRules(name, $.validator.normalizeRule(name)); + } + }, + + methods: { + + // http://docs.jquery.com/Plugins/Validation/Methods/required + required: function(value, element, param) { + // check if dependency is met + if ( !this.depend(param, element) ) + return "dependency-mismatch"; + switch( element.nodeName.toLowerCase() ) { + case 'select': + // could be an array for select-multiple or a string, both are fine this way + var val = $(element).val(); + return val && val.length > 0; + case 'input': + if ( this.checkable(element) ) + return this.getLength(value, element) > 0; + default: + return $.trim(value).length > 0; + } + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/remote + remote: function(value, element, param) { + if ( this.optional(element) ) + return "dependency-mismatch"; + + var previous = this.previousValue(element); + if (!this.settings.messages[element.name] ) + this.settings.messages[element.name] = {}; + previous.originalMessage = this.settings.messages[element.name].remote; + this.settings.messages[element.name].remote = previous.message; + + param = typeof param == "string" && {url:param} || param; + + if ( this.pending[element.name] ) { + return "pending"; + } + if ( previous.old === value ) { + return previous.valid; + } + + previous.old = value; + var validator = this; + this.startRequest(element); + var data = {}; + data[element.name] = value; + $.ajax($.extend(true, { + url: param, + mode: "abort", + port: "validate" + element.name, + dataType: "json", + data: data, + success: function(response) { + validator.settings.messages[element.name].remote = previous.originalMessage; + var valid = response === true; + if ( valid ) { + var submitted = validator.formSubmitted; + validator.prepareElement(element); + validator.formSubmitted = submitted; + validator.successList.push(element); + validator.showErrors(); + } else { + var errors = {}; + var message = response || validator.defaultMessage(element, "remote"); + errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message; + validator.showErrors(errors); + } + previous.valid = valid; + validator.stopRequest(element, valid); + } + }, param)); + return "pending"; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/minlength + minlength: function(value, element, param) { + return this.optional(element) || this.getLength($.trim(value), element) >= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/maxlength + maxlength: function(value, element, param) { + return this.optional(element) || this.getLength($.trim(value), element) <= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/rangelength + rangelength: function(value, element, param) { + var length = this.getLength($.trim(value), element); + return this.optional(element) || ( length >= param[0] && length <= param[1] ); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/min + min: function( value, element, param ) { + return this.optional(element) || value >= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/max + max: function( value, element, param ) { + return this.optional(element) || value <= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/range + range: function( value, element, param ) { + return this.optional(element) || ( value >= param[0] && value <= param[1] ); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/email + email: function(value, element) { + // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/ + return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([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])))\.?$/i.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/url + url: function(value, element) { + // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/ + 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); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/date + date: function(value, element) { + return this.optional(element) || !/Invalid|NaN/.test(new Date(value)); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/dateISO + dateISO: function(value, element) { + return this.optional(element) || /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/number + number: function(value, element) { + return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/digits + digits: function(value, element) { + return this.optional(element) || /^\d+$/.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/creditcard + // based on http://en.wikipedia.org/wiki/Luhn + creditcard: function(value, element) { + if ( this.optional(element) ) + return "dependency-mismatch"; + // accept only digits and dashes + if (/[^0-9-]+/.test(value)) + return false; + var nCheck = 0, + nDigit = 0, + bEven = false; + + value = value.replace(/\D/g, ""); + + for (var n = value.length - 1; n >= 0; n--) { + var cDigit = value.charAt(n); + var nDigit = parseInt(cDigit, 10); + if (bEven) { + if ((nDigit *= 2) > 9) + nDigit -= 9; + } + nCheck += nDigit; + bEven = !bEven; + } + + return (nCheck % 10) == 0; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/accept + accept: function(value, element, param) { + param = typeof param == "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif"; + return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i")); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/equalTo + equalTo: function(value, element, param) { + // bind to the blur event of the target in order to revalidate whenever the target field is updated + // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead + var target = $(param).unbind(".validate-equalTo").bind("blur.validate-equalTo", function() { + $(element).valid(); + }); + return value == target.val(); + } + + } + +}); + +// deprecated, use $.validator.format instead +$.format = $.validator.format; + +})(jQuery); + +// ajax mode: abort +// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]}); +// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() +;(function($) { + var pendingRequests = {}; + // Use a prefilter if available (1.5+) + if ( $.ajaxPrefilter ) { + $.ajaxPrefilter(function(settings, _, xhr) { + var port = settings.port; + if (settings.mode == "abort") { + if ( pendingRequests[port] ) { + pendingRequests[port].abort(); + } pendingRequests[port] = xhr; + } + }); + } else { + // Proxy ajax + var ajax = $.ajax; + $.ajax = function(settings) { + var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode, + port = ( "port" in settings ? settings : $.ajaxSettings ).port; + if (mode == "abort") { + if ( pendingRequests[port] ) { + pendingRequests[port].abort(); + } + + return (pendingRequests[port] = ajax.apply(this, arguments)); + } + return ajax.apply(this, arguments); + }; + } +})(jQuery); + +// provides cross-browser focusin and focusout events +// IE has native support, in other browsers, use event caputuring (neither bubbles) + +// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation +// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target +;(function($) { + // only implement if not provided by jQuery core (since 1.4) + // TODO verify if jQuery 1.4's implementation is compatible with older jQuery special-event APIs + if (!jQuery.event.special.focusin && !jQuery.event.special.focusout && document.addEventListener) { + $.each({ + focus: 'focusin', + blur: 'focusout' + }, function( original, fix ){ + $.event.special[fix] = { + setup:function() { + this.addEventListener( original, handler, true ); + }, + teardown:function() { + this.removeEventListener( original, handler, true ); + }, + handler: function(e) { + arguments[0] = $.event.fix(e); + arguments[0].type = fix; + return $.event.handle.apply(this, arguments); + } + }; + function handler(e) { + e = $.event.fix(e); + e.type = fix; + return $.event.handle.call(this, e); + } + }); + }; + $.extend($.fn, { + validateDelegate: function(delegate, type, handler) { + return this.bind(type, function(event) { + var target = $(event.target); + if (target.is(delegate)) { + return handler.apply(target, arguments); + } + }); + } + }); +})(jQuery); diff --git a/src/Test/Test/Scripts/jquery.validate.js b/src/Test/Test/Scripts/jquery.validate.js new file mode 100644 index 000000000..4ba1ad970 --- /dev/null +++ b/src/Test/Test/Scripts/jquery.validate.js @@ -0,0 +1,1162 @@ +/** +* Note: While Microsoft is not the author of this file, Microsoft is +* offering you a license subject to the terms of the Microsoft Software +* License Terms for Microsoft ASP.NET Model View Controller 3. +* Microsoft reserves all other rights. The notices below are provided +* for informational purposes only and are not the license terms under +* which Microsoft distributed this file. +* +* jQuery Validation Plugin 1.8.0 +* +* http://bassistance.de/jquery-plugins/jquery-plugin-validation/ +* http://docs.jquery.com/Plugins/Validation +* +* Copyright (c) 2006 - 2011 Jörn Zaefferer +*/ + +(function($) { + +$.extend($.fn, { + // http://docs.jquery.com/Plugins/Validation/validate + validate: function( options ) { + + // if nothing is selected, return nothing; can't chain anyway + if (!this.length) { + options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" ); + return; + } + + // check if a validator for this form was already created + var validator = $.data(this[0], 'validator'); + if ( validator ) { + return validator; + } + + validator = new $.validator( options, this[0] ); + $.data(this[0], 'validator', validator); + + if ( validator.settings.onsubmit ) { + + // allow suppresing validation by adding a cancel class to the submit button + this.find("input, button").filter(".cancel").click(function() { + validator.cancelSubmit = true; + }); + + // when a submitHandler is used, capture the submitting button + if (validator.settings.submitHandler) { + this.find("input, button").filter(":submit").click(function() { + validator.submitButton = this; + }); + } + + // validate the form on submit + this.submit( function( event ) { + if ( validator.settings.debug ) + // prevent form submit to be able to see console output + event.preventDefault(); + + function handle() { + if ( validator.settings.submitHandler ) { + if (validator.submitButton) { + // insert a hidden input as a replacement for the missing submit button + var hidden = $("").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm); + } + validator.settings.submitHandler.call( validator, validator.currentForm ); + if (validator.submitButton) { + // and clean up afterwards; thanks to no-block-scope, hidden can be referenced + hidden.remove(); + } + return false; + } + return true; + } + + // prevent submit for invalid forms or custom submit handlers + if ( validator.cancelSubmit ) { + validator.cancelSubmit = false; + return handle(); + } + if ( validator.form() ) { + if ( validator.pendingRequest ) { + validator.formSubmitted = true; + return false; + } + return handle(); + } else { + validator.focusInvalid(); + return false; + } + }); + } + + return validator; + }, + // http://docs.jquery.com/Plugins/Validation/valid + valid: function() { + if ( $(this[0]).is('form')) { + return this.validate().form(); + } else { + var valid = true; + var validator = $(this[0].form).validate(); + this.each(function() { + valid &= validator.element(this); + }); + return valid; + } + }, + // attributes: space seperated list of attributes to retrieve and remove + removeAttrs: function(attributes) { + var result = {}, + $element = this; + $.each(attributes.split(/\s/), function(index, value) { + result[value] = $element.attr(value); + $element.removeAttr(value); + }); + return result; + }, + // http://docs.jquery.com/Plugins/Validation/rules + rules: function(command, argument) { + var element = this[0]; + + if (command) { + var settings = $.data(element.form, 'validator').settings; + var staticRules = settings.rules; + var existingRules = $.validator.staticRules(element); + switch(command) { + case "add": + $.extend(existingRules, $.validator.normalizeRule(argument)); + staticRules[element.name] = existingRules; + if (argument.messages) + settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages ); + break; + case "remove": + if (!argument) { + delete staticRules[element.name]; + return existingRules; + } + var filtered = {}; + $.each(argument.split(/\s/), function(index, method) { + filtered[method] = existingRules[method]; + delete existingRules[method]; + }); + return filtered; + } + } + + var data = $.validator.normalizeRules( + $.extend( + {}, + $.validator.metadataRules(element), + $.validator.classRules(element), + $.validator.attributeRules(element), + $.validator.staticRules(element) + ), element); + + // make sure required is at front + if (data.required) { + var param = data.required; + delete data.required; + data = $.extend({required: param}, data); + } + + return data; + } +}); + +// Custom selectors +$.extend($.expr[":"], { + // http://docs.jquery.com/Plugins/Validation/blank + blank: function(a) {return !$.trim("" + a.value);}, + // http://docs.jquery.com/Plugins/Validation/filled + filled: function(a) {return !!$.trim("" + a.value);}, + // http://docs.jquery.com/Plugins/Validation/unchecked + unchecked: function(a) {return !a.checked;} +}); + +// constructor for validator +$.validator = function( options, form ) { + this.settings = $.extend( true, {}, $.validator.defaults, options ); + this.currentForm = form; + this.init(); +}; + +$.validator.format = function(source, params) { + if ( arguments.length == 1 ) + return function() { + var args = $.makeArray(arguments); + args.unshift(source); + return $.validator.format.apply( this, args ); + }; + if ( arguments.length > 2 && params.constructor != Array ) { + params = $.makeArray(arguments).slice(1); + } + if ( params.constructor != Array ) { + params = [ params ]; + } + $.each(params, function(i, n) { + source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n); + }); + return source; +}; + +$.extend($.validator, { + + defaults: { + messages: {}, + groups: {}, + rules: {}, + errorClass: "error", + validClass: "valid", + errorElement: "label", + focusInvalid: true, + errorContainer: $( [] ), + errorLabelContainer: $( [] ), + onsubmit: true, + ignore: [], + ignoreTitle: false, + onfocusin: function(element) { + this.lastActive = element; + + // hide error label and remove error class on focus if enabled + if ( this.settings.focusCleanup && !this.blockFocusCleanup ) { + this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass ); + this.addWrapper(this.errorsFor(element)).hide(); + } + }, + onfocusout: function(element) { + if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) { + this.element(element); + } + }, + onkeyup: function(element) { + if ( element.name in this.submitted || element == this.lastElement ) { + this.element(element); + } + }, + onclick: function(element) { + // click on selects, radiobuttons and checkboxes + if ( element.name in this.submitted ) + this.element(element); + // or option elements, check parent select in that case + else if (element.parentNode.name in this.submitted) + this.element(element.parentNode); + }, + highlight: function( element, errorClass, validClass ) { + $(element).addClass(errorClass).removeClass(validClass); + }, + unhighlight: function( element, errorClass, validClass ) { + $(element).removeClass(errorClass).addClass(validClass); + } + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults + setDefaults: function(settings) { + $.extend( $.validator.defaults, settings ); + }, + + messages: { + required: "This field is required.", + remote: "Please fix this field.", + email: "Please enter a valid email address.", + url: "Please enter a valid URL.", + date: "Please enter a valid date.", + dateISO: "Please enter a valid date (ISO).", + number: "Please enter a valid number.", + digits: "Please enter only digits.", + creditcard: "Please enter a valid credit card number.", + equalTo: "Please enter the same value again.", + accept: "Please enter a value with a valid extension.", + maxlength: $.validator.format("Please enter no more than {0} characters."), + minlength: $.validator.format("Please enter at least {0} characters."), + rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."), + range: $.validator.format("Please enter a value between {0} and {1}."), + max: $.validator.format("Please enter a value less than or equal to {0}."), + min: $.validator.format("Please enter a value greater than or equal to {0}.") + }, + + autoCreateRanges: false, + + prototype: { + + init: function() { + this.labelContainer = $(this.settings.errorLabelContainer); + this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm); + this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer ); + this.submitted = {}; + this.valueCache = {}; + this.pendingRequest = 0; + this.pending = {}; + this.invalid = {}; + this.reset(); + + var groups = (this.groups = {}); + $.each(this.settings.groups, function(key, value) { + $.each(value.split(/\s/), function(index, name) { + groups[name] = key; + }); + }); + var rules = this.settings.rules; + $.each(rules, function(key, value) { + rules[key] = $.validator.normalizeRule(value); + }); + + function delegate(event) { + var validator = $.data(this[0].form, "validator"), + eventType = "on" + event.type.replace(/^validate/, ""); + validator.settings[eventType] && validator.settings[eventType].call(validator, this[0] ); + } + $(this.currentForm) + .validateDelegate(":text, :password, :file, select, textarea", "focusin focusout keyup", delegate) + .validateDelegate(":radio, :checkbox, select, option", "click", delegate); + + if (this.settings.invalidHandler) + $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler); + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/form + form: function() { + this.checkForm(); + $.extend(this.submitted, this.errorMap); + this.invalid = $.extend({}, this.errorMap); + if (!this.valid()) + $(this.currentForm).triggerHandler("invalid-form", [this]); + this.showErrors(); + return this.valid(); + }, + + checkForm: function() { + this.prepareForm(); + for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) { + this.check( elements[i] ); + } + return this.valid(); + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/element + element: function( element ) { + element = this.clean( element ); + this.lastElement = element; + this.prepareElement( element ); + this.currentElements = $(element); + var result = this.check( element ); + if ( result ) { + delete this.invalid[element.name]; + } else { + this.invalid[element.name] = true; + } + if ( !this.numberOfInvalids() ) { + // Hide error containers on last error + this.toHide = this.toHide.add( this.containers ); + } + this.showErrors(); + return result; + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/showErrors + showErrors: function(errors) { + if(errors) { + // add items to error list and map + $.extend( this.errorMap, errors ); + this.errorList = []; + for ( var name in errors ) { + this.errorList.push({ + message: errors[name], + element: this.findByName(name)[0] + }); + } + // remove items from success list + this.successList = $.grep( this.successList, function(element) { + return !(element.name in errors); + }); + } + this.settings.showErrors + ? this.settings.showErrors.call( this, this.errorMap, this.errorList ) + : this.defaultShowErrors(); + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/resetForm + resetForm: function() { + if ( $.fn.resetForm ) + $( this.currentForm ).resetForm(); + this.submitted = {}; + this.prepareForm(); + this.hideErrors(); + this.elements().removeClass( this.settings.errorClass ); + }, + + numberOfInvalids: function() { + return this.objectLength(this.invalid); + }, + + objectLength: function( obj ) { + var count = 0; + for ( var i in obj ) + count++; + return count; + }, + + hideErrors: function() { + this.addWrapper( this.toHide ).hide(); + }, + + valid: function() { + return this.size() == 0; + }, + + size: function() { + return this.errorList.length; + }, + + focusInvalid: function() { + if( this.settings.focusInvalid ) { + try { + $(this.findLastActive() || this.errorList.length && this.errorList[0].element || []) + .filter(":visible") + .focus() + // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find + .trigger("focusin"); + } catch(e) { + // ignore IE throwing errors when focusing hidden elements + } + } + }, + + findLastActive: function() { + var lastActive = this.lastActive; + return lastActive && $.grep(this.errorList, function(n) { + return n.element.name == lastActive.name; + }).length == 1 && lastActive; + }, + + elements: function() { + var validator = this, + rulesCache = {}; + + // select all valid inputs inside the form (no submit or reset buttons) + // workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved + return $([]).add(this.currentForm.elements) + .filter(":input") + .not(":submit, :reset, :image, [disabled]") + .not( this.settings.ignore ) + .filter(function() { + !this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this); + + // select only the first element for each name, and only those with rules specified + if ( this.name in rulesCache || !validator.objectLength($(this).rules()) ) + return false; + + rulesCache[this.name] = true; + return true; + }); + }, + + clean: function( selector ) { + return $( selector )[0]; + }, + + errors: function() { + return $( this.settings.errorElement + "." + this.settings.errorClass, this.errorContext ); + }, + + reset: function() { + this.successList = []; + this.errorList = []; + this.errorMap = {}; + this.toShow = $([]); + this.toHide = $([]); + this.currentElements = $([]); + }, + + prepareForm: function() { + this.reset(); + this.toHide = this.errors().add( this.containers ); + }, + + prepareElement: function( element ) { + this.reset(); + this.toHide = this.errorsFor(element); + }, + + check: function( element ) { + element = this.clean( element ); + + // if radio/checkbox, validate first element in group instead + if (this.checkable(element)) { + element = this.findByName( element.name ).not(this.settings.ignore)[0]; + } + + var rules = $(element).rules(); + var dependencyMismatch = false; + for (var method in rules ) { + var rule = { method: method, parameters: rules[method] }; + try { + var result = $.validator.methods[method].call( this, element.value.replace(/\r/g, ""), element, rule.parameters ); + + // if a method indicates that the field is optional and therefore valid, + // don't mark it as valid when there are no other rules + if ( result == "dependency-mismatch" ) { + dependencyMismatch = true; + continue; + } + dependencyMismatch = false; + + if ( result == "pending" ) { + this.toHide = this.toHide.not( this.errorsFor(element) ); + return; + } + + if( !result ) { + this.formatAndAdd( element, rule ); + return false; + } + } catch(e) { + this.settings.debug && window.console && console.log("exception occured when checking element " + element.id + + ", check the '" + rule.method + "' method", e); + throw e; + } + } + if (dependencyMismatch) + return; + if ( this.objectLength(rules) ) + this.successList.push(element); + return true; + }, + + // return the custom message for the given element and validation method + // specified in the element's "messages" metadata + customMetaMessage: function(element, method) { + if (!$.metadata) + return; + + var meta = this.settings.meta + ? $(element).metadata()[this.settings.meta] + : $(element).metadata(); + + return meta && meta.messages && meta.messages[method]; + }, + + // return the custom message for the given element name and validation method + customMessage: function( name, method ) { + var m = this.settings.messages[name]; + return m && (m.constructor == String + ? m + : m[method]); + }, + + // return the first defined argument, allowing empty strings + findDefined: function() { + for(var i = 0; i < arguments.length; i++) { + if (arguments[i] !== undefined) + return arguments[i]; + } + return undefined; + }, + + defaultMessage: function( element, method) { + return this.findDefined( + this.customMessage( element.name, method ), + this.customMetaMessage( element, method ), + // title is never undefined, so handle empty string as undefined + !this.settings.ignoreTitle && element.title || undefined, + $.validator.messages[method], + "Warning: No message defined for " + element.name + "" + ); + }, + + formatAndAdd: function( element, rule ) { + var message = this.defaultMessage( element, rule.method ), + theregex = /\$?\{(\d+)\}/g; + if ( typeof message == "function" ) { + message = message.call(this, rule.parameters, element); + } else if (theregex.test(message)) { + message = jQuery.format(message.replace(theregex, '{$1}'), rule.parameters); + } + this.errorList.push({ + message: message, + element: element + }); + + this.errorMap[element.name] = message; + this.submitted[element.name] = message; + }, + + addWrapper: function(toToggle) { + if ( this.settings.wrapper ) + toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) ); + return toToggle; + }, + + defaultShowErrors: function() { + for ( var i = 0; this.errorList[i]; i++ ) { + var error = this.errorList[i]; + this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass ); + this.showLabel( error.element, error.message ); + } + if( this.errorList.length ) { + this.toShow = this.toShow.add( this.containers ); + } + if (this.settings.success) { + for ( var i = 0; this.successList[i]; i++ ) { + this.showLabel( this.successList[i] ); + } + } + if (this.settings.unhighlight) { + for ( var i = 0, elements = this.validElements(); elements[i]; i++ ) { + this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass ); + } + } + this.toHide = this.toHide.not( this.toShow ); + this.hideErrors(); + this.addWrapper( this.toShow ).show(); + }, + + validElements: function() { + return this.currentElements.not(this.invalidElements()); + }, + + invalidElements: function() { + return $(this.errorList).map(function() { + return this.element; + }); + }, + + showLabel: function(element, message) { + var label = this.errorsFor( element ); + if ( label.length ) { + // refresh error/success class + label.removeClass().addClass( this.settings.errorClass ); + + // check if we have a generated label, replace the message then + label.attr("generated") && label.html(message); + } else { + // create label + label = $("<" + this.settings.errorElement + "/>") + .attr({"for": this.idOrName(element), generated: true}) + .addClass(this.settings.errorClass) + .html(message || ""); + if ( this.settings.wrapper ) { + // make sure the element is visible, even in IE + // actually showing the wrapped element is handled elsewhere + label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent(); + } + if ( !this.labelContainer.append(label).length ) + this.settings.errorPlacement + ? this.settings.errorPlacement(label, $(element) ) + : label.insertAfter(element); + } + if ( !message && this.settings.success ) { + label.text(""); + typeof this.settings.success == "string" + ? label.addClass( this.settings.success ) + : this.settings.success( label ); + } + this.toShow = this.toShow.add(label); + }, + + errorsFor: function(element) { + var name = this.idOrName(element); + return this.errors().filter(function() { + return $(this).attr('for') == name; + }); + }, + + idOrName: function(element) { + return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name); + }, + + checkable: function( element ) { + return /radio|checkbox/i.test(element.type); + }, + + findByName: function( name ) { + // select by name and filter by form for performance over form.find("[name=...]") + var form = this.currentForm; + return $(document.getElementsByName(name)).map(function(index, element) { + return element.form == form && element.name == name && element || null; + }); + }, + + getLength: function(value, element) { + switch( element.nodeName.toLowerCase() ) { + case 'select': + return $("option:selected", element).length; + case 'input': + if( this.checkable( element) ) + return this.findByName(element.name).filter(':checked').length; + } + return value.length; + }, + + depend: function(param, element) { + return this.dependTypes[typeof param] + ? this.dependTypes[typeof param](param, element) + : true; + }, + + dependTypes: { + "boolean": function(param, element) { + return param; + }, + "string": function(param, element) { + return !!$(param, element.form).length; + }, + "function": function(param, element) { + return param(element); + } + }, + + optional: function(element) { + return !$.validator.methods.required.call(this, $.trim(element.value), element) && "dependency-mismatch"; + }, + + startRequest: function(element) { + if (!this.pending[element.name]) { + this.pendingRequest++; + this.pending[element.name] = true; + } + }, + + stopRequest: function(element, valid) { + this.pendingRequest--; + // sometimes synchronization fails, make sure pendingRequest is never < 0 + if (this.pendingRequest < 0) + this.pendingRequest = 0; + delete this.pending[element.name]; + if ( valid && this.pendingRequest == 0 && this.formSubmitted && this.form() ) { + $(this.currentForm).submit(); + this.formSubmitted = false; + } else if (!valid && this.pendingRequest == 0 && this.formSubmitted) { + $(this.currentForm).triggerHandler("invalid-form", [this]); + this.formSubmitted = false; + } + }, + + previousValue: function(element) { + return $.data(element, "previousValue") || $.data(element, "previousValue", { + old: null, + valid: true, + message: this.defaultMessage( element, "remote" ) + }); + } + + }, + + classRuleSettings: { + required: {required: true}, + email: {email: true}, + url: {url: true}, + date: {date: true}, + dateISO: {dateISO: true}, + dateDE: {dateDE: true}, + number: {number: true}, + numberDE: {numberDE: true}, + digits: {digits: true}, + creditcard: {creditcard: true} + }, + + addClassRules: function(className, rules) { + className.constructor == String ? + this.classRuleSettings[className] = rules : + $.extend(this.classRuleSettings, className); + }, + + classRules: function(element) { + var rules = {}; + var classes = $(element).attr('class'); + classes && $.each(classes.split(' '), function() { + if (this in $.validator.classRuleSettings) { + $.extend(rules, $.validator.classRuleSettings[this]); + } + }); + return rules; + }, + + attributeRules: function(element) { + var rules = {}; + var $element = $(element); + + for (var method in $.validator.methods) { + var value = $element.attr(method); + if (value) { + rules[method] = value; + } + } + + // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs + if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) { + delete rules.maxlength; + } + + return rules; + }, + + metadataRules: function(element) { + if (!$.metadata) return {}; + + var meta = $.data(element.form, 'validator').settings.meta; + return meta ? + $(element).metadata()[meta] : + $(element).metadata(); + }, + + staticRules: function(element) { + var rules = {}; + var validator = $.data(element.form, 'validator'); + if (validator.settings.rules) { + rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {}; + } + return rules; + }, + + normalizeRules: function(rules, element) { + // handle dependency check + $.each(rules, function(prop, val) { + // ignore rule when param is explicitly false, eg. required:false + if (val === false) { + delete rules[prop]; + return; + } + if (val.param || val.depends) { + var keepRule = true; + switch (typeof val.depends) { + case "string": + keepRule = !!$(val.depends, element.form).length; + break; + case "function": + keepRule = val.depends.call(element, element); + break; + } + if (keepRule) { + rules[prop] = val.param !== undefined ? val.param : true; + } else { + delete rules[prop]; + } + } + }); + + // evaluate parameters + $.each(rules, function(rule, parameter) { + rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter; + }); + + // clean number parameters + $.each(['minlength', 'maxlength', 'min', 'max'], function() { + if (rules[this]) { + rules[this] = Number(rules[this]); + } + }); + $.each(['rangelength', 'range'], function() { + if (rules[this]) { + rules[this] = [Number(rules[this][0]), Number(rules[this][1])]; + } + }); + + if ($.validator.autoCreateRanges) { + // auto-create ranges + if (rules.min && rules.max) { + rules.range = [rules.min, rules.max]; + delete rules.min; + delete rules.max; + } + if (rules.minlength && rules.maxlength) { + rules.rangelength = [rules.minlength, rules.maxlength]; + delete rules.minlength; + delete rules.maxlength; + } + } + + // To support custom messages in metadata ignore rule methods titled "messages" + if (rules.messages) { + delete rules.messages; + } + + return rules; + }, + + // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true} + normalizeRule: function(data) { + if( typeof data == "string" ) { + var transformed = {}; + $.each(data.split(/\s/), function() { + transformed[this] = true; + }); + data = transformed; + } + return data; + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/addMethod + addMethod: function(name, method, message) { + $.validator.methods[name] = method; + $.validator.messages[name] = message != undefined ? message : $.validator.messages[name]; + if (method.length < 3) { + $.validator.addClassRules(name, $.validator.normalizeRule(name)); + } + }, + + methods: { + + // http://docs.jquery.com/Plugins/Validation/Methods/required + required: function(value, element, param) { + // check if dependency is met + if ( !this.depend(param, element) ) + return "dependency-mismatch"; + switch( element.nodeName.toLowerCase() ) { + case 'select': + // could be an array for select-multiple or a string, both are fine this way + var val = $(element).val(); + return val && val.length > 0; + case 'input': + if ( this.checkable(element) ) + return this.getLength(value, element) > 0; + default: + return $.trim(value).length > 0; + } + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/remote + remote: function(value, element, param) { + if ( this.optional(element) ) + return "dependency-mismatch"; + + var previous = this.previousValue(element); + if (!this.settings.messages[element.name] ) + this.settings.messages[element.name] = {}; + previous.originalMessage = this.settings.messages[element.name].remote; + this.settings.messages[element.name].remote = previous.message; + + param = typeof param == "string" && {url:param} || param; + + if ( this.pending[element.name] ) { + return "pending"; + } + if ( previous.old === value ) { + return previous.valid; + } + + previous.old = value; + var validator = this; + this.startRequest(element); + var data = {}; + data[element.name] = value; + $.ajax($.extend(true, { + url: param, + mode: "abort", + port: "validate" + element.name, + dataType: "json", + data: data, + success: function(response) { + validator.settings.messages[element.name].remote = previous.originalMessage; + var valid = response === true; + if ( valid ) { + var submitted = validator.formSubmitted; + validator.prepareElement(element); + validator.formSubmitted = submitted; + validator.successList.push(element); + validator.showErrors(); + } else { + var errors = {}; + var message = response || validator.defaultMessage( element, "remote" ); + errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message; + validator.showErrors(errors); + } + previous.valid = valid; + validator.stopRequest(element, valid); + } + }, param)); + return "pending"; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/minlength + minlength: function(value, element, param) { + return this.optional(element) || this.getLength($.trim(value), element) >= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/maxlength + maxlength: function(value, element, param) { + return this.optional(element) || this.getLength($.trim(value), element) <= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/rangelength + rangelength: function(value, element, param) { + var length = this.getLength($.trim(value), element); + return this.optional(element) || ( length >= param[0] && length <= param[1] ); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/min + min: function( value, element, param ) { + return this.optional(element) || value >= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/max + max: function( value, element, param ) { + return this.optional(element) || value <= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/range + range: function( value, element, param ) { + return this.optional(element) || ( value >= param[0] && value <= param[1] ); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/email + email: function(value, element) { + // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/ + return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([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])))\.?$/i.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/url + url: function(value, element) { + // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/ + 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); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/date + date: function(value, element) { + return this.optional(element) || !/Invalid|NaN/.test(new Date(value)); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/dateISO + dateISO: function(value, element) { + return this.optional(element) || /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/number + number: function(value, element) { + return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/digits + digits: function(value, element) { + return this.optional(element) || /^\d+$/.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/creditcard + // based on http://en.wikipedia.org/wiki/Luhn + creditcard: function(value, element) { + if ( this.optional(element) ) + return "dependency-mismatch"; + // accept only digits and dashes + if (/[^0-9-]+/.test(value)) + return false; + var nCheck = 0, + nDigit = 0, + bEven = false; + + value = value.replace(/\D/g, ""); + + for (var n = value.length - 1; n >= 0; n--) { + var cDigit = value.charAt(n); + var nDigit = parseInt(cDigit, 10); + if (bEven) { + if ((nDigit *= 2) > 9) + nDigit -= 9; + } + nCheck += nDigit; + bEven = !bEven; + } + + return (nCheck % 10) == 0; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/accept + accept: function(value, element, param) { + param = typeof param == "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif"; + return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i")); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/equalTo + equalTo: function(value, element, param) { + // bind to the blur event of the target in order to revalidate whenever the target field is updated + // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead + var target = $(param).unbind(".validate-equalTo").bind("blur.validate-equalTo", function() { + $(element).valid(); + }); + return value == target.val(); + } + + } + +}); + +// deprecated, use $.validator.format instead +$.format = $.validator.format; + +})(jQuery); + +// ajax mode: abort +// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]}); +// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() +;(function($) { + var pendingRequests = {}; + // Use a prefilter if available (1.5+) + if ( $.ajaxPrefilter ) { + $.ajaxPrefilter(function(settings, _, xhr) { + var port = settings.port; + if (settings.mode == "abort") { + if ( pendingRequests[port] ) { + pendingRequests[port].abort(); + } + pendingRequests[port] = xhr; + } + }); + } else { + // Proxy ajax + var ajax = $.ajax; + $.ajax = function(settings) { + var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode, + port = ( "port" in settings ? settings : $.ajaxSettings ).port; + if (mode == "abort") { + if ( pendingRequests[port] ) { + pendingRequests[port].abort(); + } + return (pendingRequests[port] = ajax.apply(this, arguments)); + } + return ajax.apply(this, arguments); + }; + } +})(jQuery); + +// provides cross-browser focusin and focusout events +// IE has native support, in other browsers, use event caputuring (neither bubbles) + +// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation +// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target +;(function($) { + // only implement if not provided by jQuery core (since 1.4) + // TODO verify if jQuery 1.4's implementation is compatible with older jQuery special-event APIs + if (!jQuery.event.special.focusin && !jQuery.event.special.focusout && document.addEventListener) { + $.each({ + focus: 'focusin', + blur: 'focusout' + }, function( original, fix ){ + $.event.special[fix] = { + setup:function() { + this.addEventListener( original, handler, true ); + }, + teardown:function() { + this.removeEventListener( original, handler, true ); + }, + handler: function(e) { + arguments[0] = $.event.fix(e); + arguments[0].type = fix; + return $.event.handle.apply(this, arguments); + } + }; + function handler(e) { + e = $.event.fix(e); + e.type = fix; + return $.event.handle.call(this, e); + } + }); + }; + $.extend($.fn, { + validateDelegate: function(delegate, type, handler) { + return this.bind(type, function(event) { + var target = $(event.target); + if (target.is(delegate)) { + return handler.apply(target, arguments); + } + }); + } + }); +})(jQuery); diff --git a/src/Test/Test/Scripts/jquery.validate.min.js b/src/Test/Test/Scripts/jquery.validate.min.js new file mode 100644 index 000000000..b07c2ab2d --- /dev/null +++ b/src/Test/Test/Scripts/jquery.validate.min.js @@ -0,0 +1,53 @@ +/** +* Note: While Microsoft is not the author of this file, Microsoft is +* offering you a license subject to the terms of the Microsoft Software +* License Terms for Microsoft ASP.NET Model View Controller 3. +* Microsoft reserves all other rights. The notices below are provided +* for informational purposes only and are not the license terms under +* which Microsoft distributed this file. +* +* jQuery Validation Plugin 1.8.0 +* +* http://bassistance.de/jquery-plugins/jquery-plugin-validation/ +* http://docs.jquery.com/Plugins/Validation +* +* Copyright (c) 2006 - 2011 Jörn Zaefferer +*/ +(function(c){c.extend(c.fn,{validate:function(a){if(this.length){var b=c.data(this[0],"validator");if(b)return b;b=new c.validator(a,this[0]);c.data(this[0],"validator",b);if(b.settings.onsubmit){this.find("input, button").filter(".cancel").click(function(){b.cancelSubmit=true});b.settings.submitHandler&&this.find("input, button").filter(":submit").click(function(){b.submitButton=this});this.submit(function(d){function e(){if(b.settings.submitHandler){if(b.submitButton)var f=c("").attr("name", +b.submitButton.name).val(b.submitButton.value).appendTo(b.currentForm);b.settings.submitHandler.call(b,b.currentForm);b.submitButton&&f.remove();return false}return true}b.settings.debug&&d.preventDefault();if(b.cancelSubmit){b.cancelSubmit=false;return e()}if(b.form()){if(b.pendingRequest){b.formSubmitted=true;return false}return e()}else{b.focusInvalid();return false}})}return b}else a&&a.debug&&window.console&&console.warn("nothing selected, can't validate, returning nothing")},valid:function(){if(c(this[0]).is("form"))return this.validate().form(); +else{var a=true,b=c(this[0].form).validate();this.each(function(){a&=b.element(this)});return a}},removeAttrs:function(a){var b={},d=this;c.each(a.split(/\s/),function(e,f){b[f]=d.attr(f);d.removeAttr(f)});return b},rules:function(a,b){var d=this[0];if(a){var e=c.data(d.form,"validator").settings,f=e.rules,g=c.validator.staticRules(d);switch(a){case "add":c.extend(g,c.validator.normalizeRule(b));f[d.name]=g;if(b.messages)e.messages[d.name]=c.extend(e.messages[d.name],b.messages);break;case "remove":if(!b){delete f[d.name]; +return g}var h={};c.each(b.split(/\s/),function(j,i){h[i]=g[i];delete g[i]});return h}}d=c.validator.normalizeRules(c.extend({},c.validator.metadataRules(d),c.validator.classRules(d),c.validator.attributeRules(d),c.validator.staticRules(d)),d);if(d.required){e=d.required;delete d.required;d=c.extend({required:e},d)}return d}});c.extend(c.expr[":"],{blank:function(a){return!c.trim(""+a.value)},filled:function(a){return!!c.trim(""+a.value)},unchecked:function(a){return!a.checked}});c.validator=function(a, +b){this.settings=c.extend(true,{},c.validator.defaults,a);this.currentForm=b;this.init()};c.validator.format=function(a,b){if(arguments.length==1)return function(){var d=c.makeArray(arguments);d.unshift(a);return c.validator.format.apply(this,d)};if(arguments.length>2&&b.constructor!=Array)b=c.makeArray(arguments).slice(1);if(b.constructor!=Array)b=[b];c.each(b,function(d,e){a=a.replace(RegExp("\\{"+d+"\\}","g"),e)});return a};c.extend(c.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error", +validClass:"valid",errorElement:"label",focusInvalid:true,errorContainer:c([]),errorLabelContainer:c([]),onsubmit:true,ignore:[],ignoreTitle:false,onfocusin:function(a){this.lastActive=a;if(this.settings.focusCleanup&&!this.blockFocusCleanup){this.settings.unhighlight&&this.settings.unhighlight.call(this,a,this.settings.errorClass,this.settings.validClass);this.addWrapper(this.errorsFor(a)).hide()}},onfocusout:function(a){if(!this.checkable(a)&&(a.name in this.submitted||!this.optional(a)))this.element(a)}, +onkeyup:function(a){if(a.name in this.submitted||a==this.lastElement)this.element(a)},onclick:function(a){if(a.name in this.submitted)this.element(a);else a.parentNode.name in this.submitted&&this.element(a.parentNode)},highlight:function(a,b,d){c(a).addClass(b).removeClass(d)},unhighlight:function(a,b,d){c(a).removeClass(b).addClass(d)}},setDefaults:function(a){c.extend(c.validator.defaults,a)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.", +url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date (ISO).",number:"Please enter a valid number.",digits:"Please enter only digits.",creditcard:"Please enter a valid credit card number.",equalTo:"Please enter the same value again.",accept:"Please enter a value with a valid extension.",maxlength:c.validator.format("Please enter no more than {0} characters."),minlength:c.validator.format("Please enter at least {0} characters."),rangelength:c.validator.format("Please enter a value between {0} and {1} characters long."), +range:c.validator.format("Please enter a value between {0} and {1}."),max:c.validator.format("Please enter a value less than or equal to {0}."),min:c.validator.format("Please enter a value greater than or equal to {0}.")},autoCreateRanges:false,prototype:{init:function(){function a(e){var f=c.data(this[0].form,"validator");e="on"+e.type.replace(/^validate/,"");f.settings[e]&&f.settings[e].call(f,this[0])}this.labelContainer=c(this.settings.errorLabelContainer);this.errorContext=this.labelContainer.length&& +this.labelContainer||c(this.currentForm);this.containers=c(this.settings.errorContainer).add(this.settings.errorLabelContainer);this.submitted={};this.valueCache={};this.pendingRequest=0;this.pending={};this.invalid={};this.reset();var b=this.groups={};c.each(this.settings.groups,function(e,f){c.each(f.split(/\s/),function(g,h){b[h]=e})});var d=this.settings.rules;c.each(d,function(e,f){d[e]=c.validator.normalizeRule(f)});c(this.currentForm).validateDelegate(":text, :password, :file, select, textarea", +"focusin focusout keyup",a).validateDelegate(":radio, :checkbox, select, option","click",a);this.settings.invalidHandler&&c(this.currentForm).bind("invalid-form.validate",this.settings.invalidHandler)},form:function(){this.checkForm();c.extend(this.submitted,this.errorMap);this.invalid=c.extend({},this.errorMap);this.valid()||c(this.currentForm).triggerHandler("invalid-form",[this]);this.showErrors();return this.valid()},checkForm:function(){this.prepareForm();for(var a=0,b=this.currentElements=this.elements();b[a];a++)this.check(b[a]); +return this.valid()},element:function(a){this.lastElement=a=this.clean(a);this.prepareElement(a);this.currentElements=c(a);var b=this.check(a);if(b)delete this.invalid[a.name];else this.invalid[a.name]=true;if(!this.numberOfInvalids())this.toHide=this.toHide.add(this.containers);this.showErrors();return b},showErrors:function(a){if(a){c.extend(this.errorMap,a);this.errorList=[];for(var b in a)this.errorList.push({message:a[b],element:this.findByName(b)[0]});this.successList=c.grep(this.successList, +function(d){return!(d.name in a)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){c.fn.resetForm&&c(this.currentForm).resetForm();this.submitted={};this.prepareForm();this.hideErrors();this.elements().removeClass(this.settings.errorClass)},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(a){var b=0,d;for(d in a)b++;return b},hideErrors:function(){this.addWrapper(this.toHide).hide()}, +valid:function(){return this.size()==0},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{c(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(a){}},findLastActive:function(){var a=this.lastActive;return a&&c.grep(this.errorList,function(b){return b.element.name==a.name}).length==1&&a},elements:function(){var a=this,b={};return c([]).add(this.currentForm.elements).filter(":input").not(":submit, :reset, :image, [disabled]").not(this.settings.ignore).filter(function(){!this.name&& +a.settings.debug&&window.console&&console.error("%o has no name assigned",this);if(this.name in b||!a.objectLength(c(this).rules()))return false;return b[this.name]=true})},clean:function(a){return c(a)[0]},errors:function(){return c(this.settings.errorElement+"."+this.settings.errorClass,this.errorContext)},reset:function(){this.successList=[];this.errorList=[];this.errorMap={};this.toShow=c([]);this.toHide=c([]);this.currentElements=c([])},prepareForm:function(){this.reset();this.toHide=this.errors().add(this.containers)}, +prepareElement:function(a){this.reset();this.toHide=this.errorsFor(a)},check:function(a){a=this.clean(a);if(this.checkable(a))a=this.findByName(a.name).not(this.settings.ignore)[0];var b=c(a).rules(),d=false,e;for(e in b){var f={method:e,parameters:b[e]};try{var g=c.validator.methods[e].call(this,a.value.replace(/\r/g,""),a,f.parameters);if(g=="dependency-mismatch")d=true;else{d=false;if(g=="pending"){this.toHide=this.toHide.not(this.errorsFor(a));return}if(!g){this.formatAndAdd(a,f);return false}}}catch(h){this.settings.debug&& +window.console&&console.log("exception occured when checking element "+a.id+", check the '"+f.method+"' method",h);throw h;}}if(!d){this.objectLength(b)&&this.successList.push(a);return true}},customMetaMessage:function(a,b){if(c.metadata){var d=this.settings.meta?c(a).metadata()[this.settings.meta]:c(a).metadata();return d&&d.messages&&d.messages[b]}},customMessage:function(a,b){var d=this.settings.messages[a];return d&&(d.constructor==String?d:d[b])},findDefined:function(){for(var a=0;aWarning: No message defined for "+a.name+"")},formatAndAdd:function(a,b){var d=this.defaultMessage(a,b.method),e=/\$?\{(\d+)\}/g;if(typeof d=="function")d=d.call(this,b.parameters,a);else if(e.test(d))d=jQuery.format(d.replace(e,"{$1}"),b.parameters);this.errorList.push({message:d, +element:a});this.errorMap[a.name]=d;this.submitted[a.name]=d},addWrapper:function(a){if(this.settings.wrapper)a=a.add(a.parent(this.settings.wrapper));return a},defaultShowErrors:function(){for(var a=0;this.errorList[a];a++){var b=this.errorList[a];this.settings.highlight&&this.settings.highlight.call(this,b.element,this.settings.errorClass,this.settings.validClass);this.showLabel(b.element,b.message)}if(this.errorList.length)this.toShow=this.toShow.add(this.containers);if(this.settings.success)for(a= +0;this.successList[a];a++)this.showLabel(this.successList[a]);if(this.settings.unhighlight){a=0;for(b=this.validElements();b[a];a++)this.settings.unhighlight.call(this,b[a],this.settings.errorClass,this.settings.validClass)}this.toHide=this.toHide.not(this.toShow);this.hideErrors();this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return c(this.errorList).map(function(){return this.element})},showLabel:function(a, +b){var d=this.errorsFor(a);if(d.length){d.removeClass().addClass(this.settings.errorClass);d.attr("generated")&&d.html(b)}else{d=c("<"+this.settings.errorElement+"/>").attr({"for":this.idOrName(a),generated:true}).addClass(this.settings.errorClass).html(b||"");if(this.settings.wrapper)d=d.hide().show().wrap("<"+this.settings.wrapper+"/>").parent();this.labelContainer.append(d).length||(this.settings.errorPlacement?this.settings.errorPlacement(d,c(a)):d.insertAfter(a))}if(!b&&this.settings.success){d.text(""); +typeof this.settings.success=="string"?d.addClass(this.settings.success):this.settings.success(d)}this.toShow=this.toShow.add(d)},errorsFor:function(a){var b=this.idOrName(a);return this.errors().filter(function(){return c(this).attr("for")==b})},idOrName:function(a){return this.groups[a.name]||(this.checkable(a)?a.name:a.id||a.name)},checkable:function(a){return/radio|checkbox/i.test(a.type)},findByName:function(a){var b=this.currentForm;return c(document.getElementsByName(a)).map(function(d,e){return e.form== +b&&e.name==a&&e||null})},getLength:function(a,b){switch(b.nodeName.toLowerCase()){case "select":return c("option:selected",b).length;case "input":if(this.checkable(b))return this.findByName(b.name).filter(":checked").length}return a.length},depend:function(a,b){return this.dependTypes[typeof a]?this.dependTypes[typeof a](a,b):true},dependTypes:{"boolean":function(a){return a},string:function(a,b){return!!c(a,b.form).length},"function":function(a,b){return a(b)}},optional:function(a){return!c.validator.methods.required.call(this, +c.trim(a.value),a)&&"dependency-mismatch"},startRequest:function(a){if(!this.pending[a.name]){this.pendingRequest++;this.pending[a.name]=true}},stopRequest:function(a,b){this.pendingRequest--;if(this.pendingRequest<0)this.pendingRequest=0;delete this.pending[a.name];if(b&&this.pendingRequest==0&&this.formSubmitted&&this.form()){c(this.currentForm).submit();this.formSubmitted=false}else if(!b&&this.pendingRequest==0&&this.formSubmitted){c(this.currentForm).triggerHandler("invalid-form",[this]);this.formSubmitted= +false}},previousValue:function(a){return c.data(a,"previousValue")||c.data(a,"previousValue",{old:null,valid:true,message:this.defaultMessage(a,"remote")})}},classRuleSettings:{required:{required:true},email:{email:true},url:{url:true},date:{date:true},dateISO:{dateISO:true},dateDE:{dateDE:true},number:{number:true},numberDE:{numberDE:true},digits:{digits:true},creditcard:{creditcard:true}},addClassRules:function(a,b){a.constructor==String?this.classRuleSettings[a]=b:c.extend(this.classRuleSettings, +a)},classRules:function(a){var b={};(a=c(a).attr("class"))&&c.each(a.split(" "),function(){this in c.validator.classRuleSettings&&c.extend(b,c.validator.classRuleSettings[this])});return b},attributeRules:function(a){var b={};a=c(a);for(var d in c.validator.methods){var e=a.attr(d);if(e)b[d]=e}b.maxlength&&/-1|2147483647|524288/.test(b.maxlength)&&delete b.maxlength;return b},metadataRules:function(a){if(!c.metadata)return{};var b=c.data(a.form,"validator").settings.meta;return b?c(a).metadata()[b]: +c(a).metadata()},staticRules:function(a){var b={},d=c.data(a.form,"validator");if(d.settings.rules)b=c.validator.normalizeRule(d.settings.rules[a.name])||{};return b},normalizeRules:function(a,b){c.each(a,function(d,e){if(e===false)delete a[d];else if(e.param||e.depends){var f=true;switch(typeof e.depends){case "string":f=!!c(e.depends,b.form).length;break;case "function":f=e.depends.call(b,b)}if(f)a[d]=e.param!==undefined?e.param:true;else delete a[d]}});c.each(a,function(d,e){a[d]=c.isFunction(e)? +e(b):e});c.each(["minlength","maxlength","min","max"],function(){if(a[this])a[this]=Number(a[this])});c.each(["rangelength","range"],function(){if(a[this])a[this]=[Number(a[this][0]),Number(a[this][1])]});if(c.validator.autoCreateRanges){if(a.min&&a.max){a.range=[a.min,a.max];delete a.min;delete a.max}if(a.minlength&&a.maxlength){a.rangelength=[a.minlength,a.maxlength];delete a.minlength;delete a.maxlength}}a.messages&&delete a.messages;return a},normalizeRule:function(a){if(typeof a=="string"){var b= +{};c.each(a.split(/\s/),function(){b[this]=true});a=b}return a},addMethod:function(a,b,d){c.validator.methods[a]=b;c.validator.messages[a]=d!=undefined?d:c.validator.messages[a];b.length<3&&c.validator.addClassRules(a,c.validator.normalizeRule(a))},methods:{required:function(a,b,d){if(!this.depend(d,b))return"dependency-mismatch";switch(b.nodeName.toLowerCase()){case "select":return(a=c(b).val())&&a.length>0;case "input":if(this.checkable(b))return this.getLength(a,b)>0;default:return c.trim(a).length> +0}},remote:function(a,b,d){if(this.optional(b))return"dependency-mismatch";var e=this.previousValue(b);this.settings.messages[b.name]||(this.settings.messages[b.name]={});e.originalMessage=this.settings.messages[b.name].remote;this.settings.messages[b.name].remote=e.message;d=typeof d=="string"&&{url:d}||d;if(this.pending[b.name])return"pending";if(e.old===a)return e.valid;e.old=a;var f=this;this.startRequest(b);var g={};g[b.name]=a;c.ajax(c.extend(true,{url:d,mode:"abort",port:"validate"+b.name, +dataType:"json",data:g,success:function(h){f.settings.messages[b.name].remote=e.originalMessage;var j=h===true;if(j){var i=f.formSubmitted;f.prepareElement(b);f.formSubmitted=i;f.successList.push(b);f.showErrors()}else{i={};h=h||f.defaultMessage(b,"remote");i[b.name]=e.message=c.isFunction(h)?h(a):h;f.showErrors(i)}e.valid=j;f.stopRequest(b,j)}},d));return"pending"},minlength:function(a,b,d){return this.optional(b)||this.getLength(c.trim(a),b)>=d},maxlength:function(a,b,d){return this.optional(b)|| +this.getLength(c.trim(a),b)<=d},rangelength:function(a,b,d){a=this.getLength(c.trim(a),b);return this.optional(b)||a>=d[0]&&a<=d[1]},min:function(a,b,d){return this.optional(b)||a>=d},max:function(a,b,d){return this.optional(b)||a<=d},range:function(a,b,d){return this.optional(b)||a>=d[0]&&a<=d[1]},email:function(a,b){return this.optional(b)||/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([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])))\.?$/i.test(a)}, +url:function(a,b){return this.optional(b)||/^(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(a)}, +date:function(a,b){return this.optional(b)||!/Invalid|NaN/.test(new Date(a))},dateISO:function(a,b){return this.optional(b)||/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(a)},number:function(a,b){return this.optional(b)||/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(a)},digits:function(a,b){return this.optional(b)||/^\d+$/.test(a)},creditcard:function(a,b){if(this.optional(b))return"dependency-mismatch";if(/[^0-9-]+/.test(a))return false;var d=0,e=0,f=false;a=a.replace(/\D/g,"");for(var g=a.length-1;g>= +0;g--){e=a.charAt(g);e=parseInt(e,10);if(f)if((e*=2)>9)e-=9;d+=e;f=!f}return d%10==0},accept:function(a,b,d){d=typeof d=="string"?d.replace(/,/g,"|"):"png|jpe?g|gif";return this.optional(b)||a.match(RegExp(".("+d+")$","i"))},equalTo:function(a,b,d){d=c(d).unbind(".validate-equalTo").bind("blur.validate-equalTo",function(){c(b).valid()});return a==d.val()}}});c.format=c.validator.format})(jQuery); +(function(c){var a={};if(c.ajaxPrefilter)c.ajaxPrefilter(function(d,e,f){e=d.port;if(d.mode=="abort"){a[e]&&a[e].abort();a[e]=f}});else{var b=c.ajax;c.ajax=function(d){var e=("port"in d?d:c.ajaxSettings).port;if(("mode"in d?d:c.ajaxSettings).mode=="abort"){a[e]&&a[e].abort();return a[e]=b.apply(this,arguments)}return b.apply(this,arguments)}}})(jQuery); +(function(c){!jQuery.event.special.focusin&&!jQuery.event.special.focusout&&document.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.handle.call(this,e)}c.event.special[b]={setup:function(){this.addEventListener(a,d,true)},teardown:function(){this.removeEventListener(a,d,true)},handler:function(e){arguments[0]=c.event.fix(e);arguments[0].type=b;return c.event.handle.apply(this,arguments)}}});c.extend(c.fn,{validateDelegate:function(a, +b,d){return this.bind(b,function(e){var f=c(e.target);if(f.is(a))return d.apply(f,arguments)})}})})(jQuery); diff --git a/src/Test/Test/Scripts/jquery.validate.unobtrusive.js b/src/Test/Test/Scripts/jquery.validate.unobtrusive.js new file mode 100644 index 000000000..6d92c0d58 --- /dev/null +++ b/src/Test/Test/Scripts/jquery.validate.unobtrusive.js @@ -0,0 +1,319 @@ +/// +/// + +/*! +** Unobtrusive validation support library for jQuery and jQuery Validate +** Copyright (C) Microsoft Corporation. All rights reserved. +*/ + +/*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 */ +/*global document: false, jQuery: false */ + +(function ($) { + var $jQval = $.validator, + adapters, + data_validation = "unobtrusiveValidation"; + + function setValidationValues(options, ruleName, value) { + options.rules[ruleName] = value; + if (options.message) { + options.messages[ruleName] = options.message; + } + } + + function splitAndTrim(value) { + return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g); + } + + function getModelPrefix(fieldName) { + return fieldName.substr(0, fieldName.lastIndexOf(".") + 1); + } + + function appendModelPrefix(value, prefix) { + if (value.indexOf("*.") === 0) { + value = value.replace("*.", prefix); + } + return value; + } + + function onError(error, inputElement) { // 'this' is the form element + var container = $(this).find("[data-valmsg-for='" + inputElement[0].name + "']"), + replace = $.parseJSON(container.attr("data-valmsg-replace")) !== false; + + container.removeClass("field-validation-valid").addClass("field-validation-error"); + error.data("unobtrusiveContainer", container); + + if (replace) { + container.empty(); + error.removeClass("input-validation-error").appendTo(container); + } + else { + error.hide(); + } + } + + function onErrors(form, validator) { // 'this' is the form element + var container = $(this).find("[data-valmsg-summary=true]"), + list = container.find("ul"); + + if (list && list.length && validator.errorList.length) { + list.empty(); + container.addClass("validation-summary-errors").removeClass("validation-summary-valid"); + + $.each(validator.errorList, function () { + $("
  • ").html(this.message).appendTo(list); + }); + } + } + + function onSuccess(error) { // 'this' is the form element + var container = error.data("unobtrusiveContainer"), + replace = $.parseJSON(container.attr("data-valmsg-replace")); + + if (container) { + container.addClass("field-validation-valid").removeClass("field-validation-error"); + error.removeData("unobtrusiveContainer"); + + if (replace) { + container.empty(); + } + } + } + + function validationInfo(form) { + var $form = $(form), + result = $form.data(data_validation); + + if (!result) { + result = { + options: { // options structure passed to jQuery Validate's validate() method + errorClass: "input-validation-error", + errorElement: "span", + errorPlacement: $.proxy(onError, form), + invalidHandler: $.proxy(onErrors, form), + messages: {}, + rules: {}, + success: $.proxy(onSuccess, form) + }, + attachValidation: function () { + $form.validate(this.options); + }, + validate: function () { // a validation function that is called by unobtrusive Ajax + $form.validate(); + return $form.valid(); + } + }; + $form.data(data_validation, result); + } + + return result; + } + + $jQval.unobtrusive = { + adapters: [], + + parseElement: function (element, skipAttach) { + /// + /// Parses a single HTML element for unobtrusive validation attributes. + /// + /// The HTML element to be parsed. + /// [Optional] true to skip attaching the + /// validation to the form. If parsing just this single element, you should specify true. + /// If parsing several elements, you should specify false, and manually attach the validation + /// to the form when you are finished. The default is false. + var $element = $(element), + form = $element.parents("form")[0], + valInfo, rules, messages; + + if (!form) { // Cannot do client-side validation without a form + return; + } + + valInfo = validationInfo(form); + valInfo.options.rules[element.name] = rules = {}; + valInfo.options.messages[element.name] = messages = {}; + + $.each(this.adapters, function () { + var prefix = "data-val-" + this.name, + message = $element.attr(prefix), + paramValues = {}; + + if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy) + prefix += "-"; + + $.each(this.params, function () { + paramValues[this] = $element.attr(prefix + this); + }); + + this.adapt({ + element: element, + form: form, + message: message, + params: paramValues, + rules: rules, + messages: messages + }); + } + }); + + jQuery.extend(rules, { "__dummy__": true }); + + if (!skipAttach) { + valInfo.attachValidation(); + } + }, + + parse: function (selector) { + /// + /// Parses all the HTML elements in the specified selector. It looks for input elements decorated + /// with the [data-val=true] attribute value and enables validation according to the data-val-* + /// attribute values. + /// + /// Any valid jQuery selector. + $(selector).find(":input[data-val=true]").each(function () { + $jQval.unobtrusive.parseElement(this, true); + }); + + $("form").each(function () { + var info = validationInfo(this); + if (info) { + info.attachValidation(); + } + }); + } + }; + + adapters = $jQval.unobtrusive.adapters; + + adapters.add = function (adapterName, params, fn) { + /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation. + /// The name of the adapter to be added. This matches the name used + /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). + /// [Optional] An array of parameter names (strings) that will + /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and + /// mmmm is the parameter name). + /// The function to call, which adapts the values from the HTML + /// attributes into jQuery Validate rules and/or messages. + /// + if (!fn) { // Called with no params, just a function + fn = params; + params = []; + } + this.push({ name: adapterName, params: params, adapt: fn }); + return this; + }; + + adapters.addBool = function (adapterName, ruleName) { + /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where + /// the jQuery Validate validation rule has no parameter values. + /// The name of the adapter to be added. This matches the name used + /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). + /// [Optional] The name of the jQuery Validate rule. If not provided, the value + /// of adapterName will be used instead. + /// + return this.add(adapterName, function (options) { + setValidationValues(options, ruleName || adapterName, true); + }); + }; + + adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) { + /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where + /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and + /// one for min-and-max). The HTML parameters are expected to be named -min and -max. + /// The name of the adapter to be added. This matches the name used + /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). + /// The name of the jQuery Validate rule to be used when you only + /// have a minimum value. + /// The name of the jQuery Validate rule to be used when you only + /// have a maximum value. + /// The name of the jQuery Validate rule to be used when you + /// have both a minimum and maximum value. + /// [Optional] The name of the HTML attribute that + /// contains the minimum value. The default is "min". + /// [Optional] The name of the HTML attribute that + /// contains the maximum value. The default is "max". + /// + return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) { + var min = options.params.min, + max = options.params.max; + + if (min && max) { + setValidationValues(options, minMaxRuleName, [min, max]); + } + else if (min) { + setValidationValues(options, minRuleName, min); + } + else if (max) { + setValidationValues(options, maxRuleName, max); + } + }); + }; + + adapters.addSingleVal = function (adapterName, attribute, ruleName) { + /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where + /// the jQuery Validate validation rule has a single value. + /// The name of the adapter to be added. This matches the name used + /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name). + /// [Optional] The name of the HTML attribute that contains the value. + /// The default is "val". + /// [Optional] The name of the jQuery Validate rule. If not provided, the value + /// of adapterName will be used instead. + /// + return this.add(adapterName, [attribute || "val"], function (options) { + setValidationValues(options, ruleName || adapterName, options.params[attribute]); + }); + }; + + $jQval.addMethod("__dummy__", function (value, element, params) { + return true; + }); + + $jQval.addMethod("regex", function (value, element, params) { + var match; + if (this.optional(element)) { + return true; + } + + match = new RegExp(params).exec(value); + return (match && (match.index === 0) && (match[0].length === value.length)); + }); + + adapters.addSingleVal("accept", "exts").addSingleVal("regex", "pattern"); + adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"); + adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range"); + adapters.add("equalto", ["other"], function (options) { + var prefix = getModelPrefix(options.element.name), + other = options.params.other, + fullOtherName = appendModelPrefix(other, prefix), + element = $(options.form).find(":input[name=" + fullOtherName + "]")[0]; + + setValidationValues(options, "equalTo", element); + }); + adapters.add("required", function (options) { + // jQuery Validate equates "required" with "mandatory" for checkbox elements + if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") { + setValidationValues(options, "required", true); + } + }); + adapters.add("remote", ["url", "type", "additionalfields"], function (options) { + var value = { + url: options.params.url, + type: options.params.type || "GET", + data: {} + }, + prefix = getModelPrefix(options.element.name); + + $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) { + var paramName = appendModelPrefix(fieldName, prefix); + value.data[paramName] = function () { + return $(options.form).find(":input[name='" + paramName + "']").val(); + }; + }); + + setValidationValues(options, "remote", value); + }); + + $(function () { + $jQval.unobtrusive.parse(document); + }); +}(jQuery)); \ No newline at end of file diff --git a/src/Test/Test/Scripts/jquery.validate.unobtrusive.min.js b/src/Test/Test/Scripts/jquery.validate.unobtrusive.min.js new file mode 100644 index 000000000..e0d8fd5c1 --- /dev/null +++ b/src/Test/Test/Scripts/jquery.validate.unobtrusive.min.js @@ -0,0 +1,5 @@ +/* +** Unobtrusive validation support library for jQuery and jQuery Validate +** Copyright (C) Microsoft Corporation. All rights reserved. +*/ +(function(a){var d=a.validator,b,f="unobtrusiveValidation";function c(a,b,c){a.rules[b]=c;if(a.message)a.messages[b]=a.message}function i(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function g(a){return a.substr(0,a.lastIndexOf(".")+1)}function e(a,b){if(a.indexOf("*.")===0)a=a.replace("*.",b);return a}function l(c,d){var b=a(this).find("[data-valmsg-for='"+d[0].name+"']"),e=a.parseJSON(b.attr("data-valmsg-replace"))!==false;b.removeClass("field-validation-valid").addClass("field-validation-error");c.data("unobtrusiveContainer",b);if(e){b.empty();c.removeClass("input-validation-error").appendTo(b)}else c.hide()}function k(e,d){var c=a(this).find("[data-valmsg-summary=true]"),b=c.find("ul");if(b&&b.length&&d.errorList.length){b.empty();c.addClass("validation-summary-errors").removeClass("validation-summary-valid");a.each(d.errorList,function(){a("
  • ").html(this.message).appendTo(b)})}}function j(c){var b=c.data("unobtrusiveContainer"),d=a.parseJSON(b.attr("data-valmsg-replace"));if(b){b.addClass("field-validation-valid").removeClass("field-validation-error");c.removeData("unobtrusiveContainer");d&&b.empty()}}function h(d){var b=a(d),c=b.data(f);if(!c){c={options:{errorClass:"input-validation-error",errorElement:"span",errorPlacement:a.proxy(l,d),invalidHandler:a.proxy(k,d),messages:{},rules:{},success:a.proxy(j,d)},attachValidation:function(){b.validate(this.options)},validate:function(){b.validate();return b.valid()}};b.data(f,c)}return c}d.unobtrusive={adapters:[],parseElement:function(b,i){var d=a(b),f=d.parents("form")[0],c,e,g;if(!f)return;c=h(f);c.options.rules[b.name]=e={};c.options.messages[b.name]=g={};a.each(this.adapters,function(){var c="data-val-"+this.name,i=d.attr(c),h={};if(i!==undefined){c+="-";a.each(this.params,function(){h[this]=d.attr(c+this)});this.adapt({element:b,form:f,message:i,params:h,rules:e,messages:g})}});jQuery.extend(e,{__dummy__:true});!i&&c.attachValidation()},parse:function(b){a(b).find(":input[data-val=true]").each(function(){d.unobtrusive.parseElement(this,true)});a("form").each(function(){var a=h(this);a&&a.attachValidation()})}};b=d.unobtrusive.adapters;b.add=function(c,a,b){if(!b){b=a;a=[]}this.push({name:c,params:a,adapt:b});return this};b.addBool=function(a,b){return this.add(a,function(d){c(d,b||a,true)})};b.addMinMax=function(e,g,f,a,d,b){return this.add(e,[d||"min",b||"max"],function(b){var e=b.params.min,d=b.params.max;if(e&&d)c(b,a,[e,d]);else if(e)c(b,g,e);else d&&c(b,f,d)})};b.addSingleVal=function(a,b,d){return this.add(a,[b||"val"],function(e){c(e,d||a,e.params[b])})};d.addMethod("__dummy__",function(){return true});d.addMethod("regex",function(b,c,d){var a;if(this.optional(c))return true;a=(new RegExp(d)).exec(b);return a&&a.index===0&&a[0].length===b.length});b.addSingleVal("accept","exts").addSingleVal("regex","pattern");b.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");b.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range");b.add("equalto",["other"],function(b){var h=g(b.element.name),i=b.params.other,d=e(i,h),f=a(b.form).find(":input[name="+d+"]")[0];c(b,"equalTo",f)});b.add("required",function(a){(a.element.tagName.toUpperCase()!=="INPUT"||a.element.type.toUpperCase()!=="CHECKBOX")&&c(a,"required",true)});b.add("remote",["url","type","additionalfields"],function(b){var d={url:b.params.url,type:b.params.type||"GET",data:{}},f=g(b.element.name);a.each(i(b.params.additionalfields||b.element.name),function(h,g){var c=e(g,f);d.data[c]=function(){return a(b.form).find(":input[name='"+c+"']").val()}});c(b,"remote",d)});a(function(){d.unobtrusive.parse(document)})})(jQuery); \ No newline at end of file diff --git a/src/Test/Test/Scripts/modernizr-1.7.js b/src/Test/Test/Scripts/modernizr-1.7.js new file mode 100644 index 000000000..7bc212a8c --- /dev/null +++ b/src/Test/Test/Scripts/modernizr-1.7.js @@ -0,0 +1,969 @@ +/*! +* Note: While Microsoft is not the author of this file, Microsoft is +* offering you a license subject to the terms of the Microsoft Software +* License Terms for Microsoft ASP.NET Model View Controller 3. +* Microsoft reserves all other rights. The notices below are provided +* for informational purposes only and are not the license terms under +* which Microsoft distributed this file. +* +* Modernizr v1.7 +* http://www.modernizr.com +* +* Developed by: +* - Faruk Ates http://farukat.es/ +* - Paul Irish http://paulirish.com/ +* +* Copyright (c) 2009-2011 +*/ + + +/* + * Modernizr is a script that detects native CSS3 and HTML5 features + * available in the current UA and provides an object containing all + * features with a true/false value, depending on whether the UA has + * native support for it or not. + * + * Modernizr will also add classes to the element of the page, + * one for each feature it detects. If the UA supports it, a class + * like "cssgradients" will be added. If not, the class name will be + * "no-cssgradients". This allows for simple if-conditionals in your + * CSS, giving you fine control over the look & feel of your website. + * + * @author Faruk Ates + * @author Paul Irish + * @copyright (c) 2009-2011 Faruk Ates. + * @contributor Ben Alman + */ + +window.Modernizr = (function(window,document,undefined){ + + var version = '1.7', + + ret = {}, + + /** + * !! DEPRECATED !! + * + * enableHTML5 is a private property for advanced use only. If enabled, + * it will make Modernizr.init() run through a brief while() loop in + * which it will create all HTML5 elements in the DOM to allow for + * styling them in Internet Explorer, which does not recognize any + * non-HTML4 elements unless created in the DOM this way. + * + * enableHTML5 is ON by default. + * + * The enableHTML5 toggle option is DEPRECATED as per 1.6, and will be + * replaced in 2.0 in lieu of the modular, configurable nature of 2.0. + */ + enableHTML5 = true, + + + docElement = document.documentElement, + docHead = document.head || document.getElementsByTagName('head')[0], + + /** + * Create our "modernizr" element that we do most feature tests on. + */ + mod = 'modernizr', + modElem = document.createElement( mod ), + m_style = modElem.style, + + /** + * Create the input element for various Web Forms feature tests. + */ + inputElem = document.createElement( 'input' ), + + smile = ':)', + + tostring = Object.prototype.toString, + + // List of property values to set for css tests. See ticket #21 + prefixes = ' -webkit- -moz- -o- -ms- -khtml- '.split(' '), + + // Following spec is to expose vendor-specific style properties as: + // elem.style.WebkitBorderRadius + // and the following would be incorrect: + // elem.style.webkitBorderRadius + + // Webkit ghosts their properties in lowercase but Opera & Moz do not. + // Microsoft foregoes prefixes entirely <= IE8, but appears to + // use a lowercase `ms` instead of the correct `Ms` in IE9 + + // More here: http://github.com/Modernizr/Modernizr/issues/issue/21 + domPrefixes = 'Webkit Moz O ms Khtml'.split(' '), + + ns = {'svg': 'http://www.w3.org/2000/svg'}, + + tests = {}, + inputs = {}, + attrs = {}, + + classes = [], + + featurename, // used in testing loop + + + + // todo: consider using http://javascript.nwbox.com/CSSSupport/css-support.js instead + testMediaQuery = function(mq){ + + var st = document.createElement('style'), + div = document.createElement('div'), + ret; + + st.textContent = mq + '{#modernizr{height:3px}}'; + docHead.appendChild(st); + div.id = 'modernizr'; + docElement.appendChild(div); + + ret = div.offsetHeight === 3; + + st.parentNode.removeChild(st); + div.parentNode.removeChild(div); + + return !!ret; + + }, + + + /** + * isEventSupported determines if a given element supports the given event + * function from http://yura.thinkweb2.com/isEventSupported/ + */ + isEventSupported = (function(){ + + var TAGNAMES = { + 'select':'input','change':'input', + 'submit':'form','reset':'form', + 'error':'img','load':'img','abort':'img' + }; + + function isEventSupported(eventName, element) { + + element = element || document.createElement(TAGNAMES[eventName] || 'div'); + eventName = 'on' + eventName; + + // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those + var isSupported = (eventName in element); + + if (!isSupported) { + // If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element + if (!element.setAttribute) { + element = document.createElement('div'); + } + if (element.setAttribute && element.removeAttribute) { + element.setAttribute(eventName, ''); + isSupported = is(element[eventName], 'function'); + + // If property was created, "remove it" (by setting value to `undefined`) + if (!is(element[eventName], undefined)) { + element[eventName] = undefined; + } + element.removeAttribute(eventName); + } + } + + element = null; + return isSupported; + } + return isEventSupported; + })(); + + + // hasOwnProperty shim by kangax needed for Safari 2.0 support + var _hasOwnProperty = ({}).hasOwnProperty, hasOwnProperty; + if (!is(_hasOwnProperty, undefined) && !is(_hasOwnProperty.call, undefined)) { + hasOwnProperty = function (object, property) { + return _hasOwnProperty.call(object, property); + }; + } + else { + hasOwnProperty = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */ + return ((property in object) && is(object.constructor.prototype[property], undefined)); + }; + } + + /** + * set_css applies given styles to the Modernizr DOM node. + */ + function set_css( str ) { + m_style.cssText = str; + } + + /** + * set_css_all extrapolates all vendor-specific css strings. + */ + function set_css_all( str1, str2 ) { + return set_css(prefixes.join(str1 + ';') + ( str2 || '' )); + } + + /** + * is returns a boolean for if typeof obj is exactly type. + */ + function is( obj, type ) { + return typeof obj === type; + } + + /** + * contains returns a boolean for if substr is found within str. + */ + function contains( str, substr ) { + return (''+str).indexOf( substr ) !== -1; + } + + /** + * test_props is a generic CSS / DOM property test; if a browser supports + * a certain property, it won't return undefined for it. + * A supported CSS property returns empty string when its not yet set. + */ + function test_props( props, callback ) { + for ( var i in props ) { + if ( m_style[ props[i] ] !== undefined && ( !callback || callback( props[i], modElem ) ) ) { + return true; + } + } + } + + /** + * test_props_all tests a list of DOM properties we want to check against. + * We specify literally ALL possible (known and/or likely) properties on + * the element including the non-vendor prefixed one, for forward- + * compatibility. + */ + function test_props_all( prop, callback ) { + + var uc_prop = prop.charAt(0).toUpperCase() + prop.substr(1), + props = (prop + ' ' + domPrefixes.join(uc_prop + ' ') + uc_prop).split(' '); + + return !!test_props( props, callback ); + } + + + /** + * Tests + * ----- + */ + + tests['flexbox'] = function() { + /** + * set_prefixed_value_css sets the property of a specified element + * adding vendor prefixes to the VALUE of the property. + * @param {Element} element + * @param {string} property The property name. This will not be prefixed. + * @param {string} value The value of the property. This WILL be prefixed. + * @param {string=} extra Additional CSS to append unmodified to the end of + * the CSS string. + */ + function set_prefixed_value_css(element, property, value, extra) { + property += ':'; + element.style.cssText = (property + prefixes.join(value + ';' + property)).slice(0, -property.length) + (extra || ''); + } + + /** + * set_prefixed_property_css sets the property of a specified element + * adding vendor prefixes to the NAME of the property. + * @param {Element} element + * @param {string} property The property name. This WILL be prefixed. + * @param {string} value The value of the property. This will not be prefixed. + * @param {string=} extra Additional CSS to append unmodified to the end of + * the CSS string. + */ + function set_prefixed_property_css(element, property, value, extra) { + element.style.cssText = prefixes.join(property + ':' + value + ';') + (extra || ''); + } + + var c = document.createElement('div'), + elem = document.createElement('div'); + + set_prefixed_value_css(c, 'display', 'box', 'width:42px;padding:0;'); + set_prefixed_property_css(elem, 'box-flex', '1', 'width:10px;'); + + c.appendChild(elem); + docElement.appendChild(c); + + var ret = elem.offsetWidth === 42; + + c.removeChild(elem); + docElement.removeChild(c); + + return ret; + }; + + // On the S60 and BB Storm, getContext exists, but always returns undefined + // http://github.com/Modernizr/Modernizr/issues/issue/97/ + + tests['canvas'] = function() { + var elem = document.createElement( 'canvas' ); + return !!(elem.getContext && elem.getContext('2d')); + }; + + tests['canvastext'] = function() { + return !!(ret['canvas'] && is(document.createElement( 'canvas' ).getContext('2d').fillText, 'function')); + }; + + // This WebGL test false positives in FF depending on graphics hardware. But really it's quite impossible to know + // wether webgl will succeed until after you create the context. You might have hardware that can support + // a 100x100 webgl canvas, but will not support a 1000x1000 webgl canvas. So this feature inference is weak, + // but intentionally so. + tests['webgl'] = function(){ + return !!window.WebGLRenderingContext; + }; + + /* + * The Modernizr.touch test only indicates if the browser supports + * touch events, which does not necessarily reflect a touchscreen + * device, as evidenced by tablets running Windows 7 or, alas, + * the Palm Pre / WebOS (touch) phones. + * + * Additionally, Chrome (desktop) used to lie about its support on this, + * but that has since been rectified: http://crbug.com/36415 + * + * We also test for Firefox 4 Multitouch Support. + * + * For more info, see: http://modernizr.github.com/Modernizr/touch.html + */ + + tests['touch'] = function() { + + return ('ontouchstart' in window) || testMediaQuery('@media ('+prefixes.join('touch-enabled),(')+'modernizr)'); + + }; + + + /** + * geolocation tests for the new Geolocation API specification. + * This test is a standards compliant-only test; for more complete + * testing, including a Google Gears fallback, please see: + * http://code.google.com/p/geo-location-javascript/ + * or view a fallback solution using google's geo API: + * http://gist.github.com/366184 + */ + tests['geolocation'] = function() { + return !!navigator.geolocation; + }; + + // Per 1.6: + // This used to be Modernizr.crosswindowmessaging but the longer + // name has been deprecated in favor of a shorter and property-matching one. + // The old API is still available in 1.6, but as of 2.0 will throw a warning, + // and in the first release thereafter disappear entirely. + tests['postmessage'] = function() { + return !!window.postMessage; + }; + + // Web SQL database detection is tricky: + + // In chrome incognito mode, openDatabase is truthy, but using it will + // throw an exception: http://crbug.com/42380 + // We can create a dummy database, but there is no way to delete it afterwards. + + // Meanwhile, Safari users can get prompted on any database creation. + // If they do, any page with Modernizr will give them a prompt: + // http://github.com/Modernizr/Modernizr/issues/closed#issue/113 + + // We have chosen to allow the Chrome incognito false positive, so that Modernizr + // doesn't litter the web with these test databases. As a developer, you'll have + // to account for this gotcha yourself. + tests['websqldatabase'] = function() { + var result = !!window.openDatabase; + /* if (result){ + try { + result = !!openDatabase( mod + "testdb", "1.0", mod + "testdb", 2e4); + } catch(e) { + } + } */ + return result; + }; + + // Vendors have inconsistent prefixing with the experimental Indexed DB: + // - Firefox is shipping indexedDB in FF4 as moz_indexedDB + // - Webkit's implementation is accessible through webkitIndexedDB + // We test both styles. + tests['indexedDB'] = function(){ + for (var i = -1, len = domPrefixes.length; ++i < len; ){ + var prefix = domPrefixes[i].toLowerCase(); + if (window[prefix + '_indexedDB'] || window[prefix + 'IndexedDB']){ + return true; + } + } + return false; + }; + + // documentMode logic from YUI to filter out IE8 Compat Mode + // which false positives. + tests['hashchange'] = function() { + return isEventSupported('hashchange', window) && ( document.documentMode === undefined || document.documentMode > 7 ); + }; + + // Per 1.6: + // This used to be Modernizr.historymanagement but the longer + // name has been deprecated in favor of a shorter and property-matching one. + // The old API is still available in 1.6, but as of 2.0 will throw a warning, + // and in the first release thereafter disappear entirely. + tests['history'] = function() { + return !!(window.history && history.pushState); + }; + + tests['draganddrop'] = function() { + return isEventSupported('dragstart') && isEventSupported('drop'); + }; + + tests['websockets'] = function(){ + return ('WebSocket' in window); + }; + + + // http://css-tricks.com/rgba-browser-support/ + tests['rgba'] = function() { + // Set an rgba() color and check the returned value + + set_css( 'background-color:rgba(150,255,150,.5)' ); + + return contains( m_style.backgroundColor, 'rgba' ); + }; + + tests['hsla'] = function() { + // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally, + // except IE9 who retains it as hsla + + set_css('background-color:hsla(120,40%,100%,.5)' ); + + return contains( m_style.backgroundColor, 'rgba' ) || contains( m_style.backgroundColor, 'hsla' ); + }; + + tests['multiplebgs'] = function() { + // Setting multiple images AND a color on the background shorthand property + // and then querying the style.background property value for the number of + // occurrences of "url(" is a reliable method for detecting ACTUAL support for this! + + set_css( 'background:url(//:),url(//:),red url(//:)' ); + + // If the UA supports multiple backgrounds, there should be three occurrences + // of the string "url(" in the return value for elem_style.background + + return new RegExp("(url\\s*\\(.*?){3}").test(m_style.background); + }; + + + // In testing support for a given CSS property, it's legit to test: + // `elem.style[styleName] !== undefined` + // If the property is supported it will return an empty string, + // if unsupported it will return undefined. + + // We'll take advantage of this quick test and skip setting a style + // on our modernizr element, but instead just testing undefined vs + // empty string. + + + tests['backgroundsize'] = function() { + return test_props_all( 'backgroundSize' ); + }; + + tests['borderimage'] = function() { + return test_props_all( 'borderImage' ); + }; + + + // Super comprehensive table about all the unique implementations of + // border-radius: http://muddledramblings.com/table-of-css3-border-radius-compliance + + tests['borderradius'] = function() { + return test_props_all( 'borderRadius', '', function( prop ) { + return contains( prop, 'orderRadius' ); + }); + }; + + // WebOS unfortunately false positives on this test. + tests['boxshadow'] = function() { + return test_props_all( 'boxShadow' ); + }; + + // FF3.0 will false positive on this test + tests['textshadow'] = function(){ + return document.createElement('div').style.textShadow === ''; + }; + + + tests['opacity'] = function() { + // Browsers that actually have CSS Opacity implemented have done so + // according to spec, which means their return values are within the + // range of [0.0,1.0] - including the leading zero. + + set_css_all( 'opacity:.55' ); + + // The non-literal . in this regex is intentional: + // German Chrome returns this value as 0,55 + // https://github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632 + return /^0.55$/.test(m_style.opacity); + }; + + + tests['cssanimations'] = function() { + return test_props_all( 'animationName' ); + }; + + + tests['csscolumns'] = function() { + return test_props_all( 'columnCount' ); + }; + + + tests['cssgradients'] = function() { + /** + * For CSS Gradients syntax, please see: + * http://webkit.org/blog/175/introducing-css-gradients/ + * https://developer.mozilla.org/en/CSS/-moz-linear-gradient + * https://developer.mozilla.org/en/CSS/-moz-radial-gradient + * http://dev.w3.org/csswg/css3-images/#gradients- + */ + + var str1 = 'background-image:', + str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));', + str3 = 'linear-gradient(left top,#9f9, white);'; + + set_css( + (str1 + prefixes.join(str2 + str1) + prefixes.join(str3 + str1)).slice(0,-str1.length) + ); + + return contains( m_style.backgroundImage, 'gradient' ); + }; + + + tests['cssreflections'] = function() { + return test_props_all( 'boxReflect' ); + }; + + + tests['csstransforms'] = function() { + return !!test_props([ 'transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform' ]); + }; + + + tests['csstransforms3d'] = function() { + + var ret = !!test_props([ 'perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective' ]); + + // Webkit’s 3D transforms are passed off to the browser's own graphics renderer. + // It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in + // some conditions. As a result, Webkit typically recognizes the syntax but + // will sometimes throw a false positive, thus we must do a more thorough check: + if (ret && 'webkitPerspective' in docElement.style){ + + // Webkit allows this media query to succeed only if the feature is enabled. + // `@media (transform-3d),(-o-transform-3d),(-moz-transform-3d),(-ms-transform-3d),(-webkit-transform-3d),(modernizr){ ... }` + ret = testMediaQuery('@media ('+prefixes.join('transform-3d),(')+'modernizr)'); + } + return ret; + }; + + + tests['csstransitions'] = function() { + return test_props_all( 'transitionProperty' ); + }; + + + // @font-face detection routine by Diego Perini + // http://javascript.nwbox.com/CSSSupport/ + tests['fontface'] = function(){ + + var + sheet, bool, + head = docHead || docElement, + style = document.createElement("style"), + impl = document.implementation || { hasFeature: function() { return false; } }; + + style.type = 'text/css'; + head.insertBefore(style, head.firstChild); + sheet = style.sheet || style.styleSheet; + + var supportAtRule = impl.hasFeature('CSS2', '') ? + function(rule) { + if (!(sheet && rule)) return false; + var result = false; + try { + sheet.insertRule(rule, 0); + result = (/src/i).test(sheet.cssRules[0].cssText); + sheet.deleteRule(sheet.cssRules.length - 1); + } catch(e) { } + return result; + } : + function(rule) { + if (!(sheet && rule)) return false; + sheet.cssText = rule; + + return sheet.cssText.length !== 0 && (/src/i).test(sheet.cssText) && + sheet.cssText + .replace(/\r+|\n+/g, '') + .indexOf(rule.split(' ')[0]) === 0; + }; + + bool = supportAtRule('@font-face { font-family: "font"; src: url(data:,); }'); + head.removeChild(style); + return bool; + }; + + + // These tests evaluate support of the video/audio elements, as well as + // testing what types of content they support. + // + // We're using the Boolean constructor here, so that we can extend the value + // e.g. Modernizr.video // true + // Modernizr.video.ogg // 'probably' + // + // Codec values from : http://github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845 + // thx to NielsLeenheer and zcorpan + + // Note: in FF 3.5.1 and 3.5.0, "no" was a return value instead of empty string. + // Modernizr does not normalize for that. + + tests['video'] = function() { + var elem = document.createElement('video'), + bool = !!elem.canPlayType; + + if (bool){ + bool = new Boolean(bool); + bool.ogg = elem.canPlayType('video/ogg; codecs="theora"'); + + // Workaround required for IE9, which doesn't report video support without audio codec specified. + // bug 599718 @ msft connect + var h264 = 'video/mp4; codecs="avc1.42E01E'; + bool.h264 = elem.canPlayType(h264 + '"') || elem.canPlayType(h264 + ', mp4a.40.2"'); + + bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"'); + } + return bool; + }; + + tests['audio'] = function() { + var elem = document.createElement('audio'), + bool = !!elem.canPlayType; + + if (bool){ + bool = new Boolean(bool); + bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"'); + bool.mp3 = elem.canPlayType('audio/mpeg;'); + + // Mimetypes accepted: + // https://developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements + // http://bit.ly/iphoneoscodecs + bool.wav = elem.canPlayType('audio/wav; codecs="1"'); + bool.m4a = elem.canPlayType('audio/x-m4a;') || elem.canPlayType('audio/aac;'); + } + return bool; + }; + + + // Firefox has made these tests rather unfun. + + // In FF4, if disabled, window.localStorage should === null. + + // Normally, we could not test that directly and need to do a + // `('localStorage' in window) && ` test first because otherwise Firefox will + // throw http://bugzil.la/365772 if cookies are disabled + + // However, in Firefox 4 betas, if dom.storage.enabled == false, just mentioning + // the property will throw an exception. http://bugzil.la/599479 + // This looks to be fixed for FF4 Final. + + // Because we are forced to try/catch this, we'll go aggressive. + + // FWIW: IE8 Compat mode supports these features completely: + // http://www.quirksmode.org/dom/html5.html + // But IE8 doesn't support either with local files + + tests['localstorage'] = function() { + try { + return !!localStorage.getItem; + } catch(e) { + return false; + } + }; + + tests['sessionstorage'] = function() { + try { + return !!sessionStorage.getItem; + } catch(e){ + return false; + } + }; + + + tests['webWorkers'] = function () { + return !!window.Worker; + }; + + + tests['applicationcache'] = function() { + return !!window.applicationCache; + }; + + + // Thanks to Erik Dahlstrom + tests['svg'] = function(){ + return !!document.createElementNS && !!document.createElementNS(ns.svg, "svg").createSVGRect; + }; + + tests['inlinesvg'] = function() { + var div = document.createElement('div'); + div.innerHTML = ''; + return (div.firstChild && div.firstChild.namespaceURI) == ns.svg; + }; + + // Thanks to F1lt3r and lucideer + // http://github.com/Modernizr/Modernizr/issues#issue/35 + tests['smil'] = function(){ + return !!document.createElementNS && /SVG/.test(tostring.call(document.createElementNS(ns.svg,'animate'))); + }; + + tests['svgclippaths'] = function(){ + // Possibly returns a false positive in Safari 3.2? + return !!document.createElementNS && /SVG/.test(tostring.call(document.createElementNS(ns.svg,'clipPath'))); + }; + + + // input features and input types go directly onto the ret object, bypassing the tests loop. + // Hold this guy to execute in a moment. + function webforms(){ + + // Run through HTML5's new input attributes to see if the UA understands any. + // We're using f which is the element created early on + // Mike Taylr has created a comprehensive resource for testing these attributes + // when applied to all input types: + // http://miketaylr.com/code/input-type-attr.html + // spec: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary + ret['input'] = (function(props) { + for (var i = 0, len = props.length; i>BEGIN IEPP + // Enable HTML 5 elements for styling in IE. + // fyi: jscript version does not reflect trident version + // therefore ie9 in ie7 mode will still have a jScript v.9 + if ( enableHTML5 && window.attachEvent && (function(){ var elem = document.createElement("div"); + elem.innerHTML = ""; + return elem.childNodes.length !== 1; })()) { + // iepp v1.6.2 by @jon_neal : code.google.com/p/ie-print-protector + (function(win, doc) { + var elems = 'abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video', + elemsArr = elems.split('|'), + elemsArrLen = elemsArr.length, + elemRegExp = new RegExp('(^|\\s)('+elems+')', 'gi'), + tagRegExp = new RegExp('<(\/*)('+elems+')', 'gi'), + ruleRegExp = new RegExp('(^|[^\\n]*?\\s)('+elems+')([^\\n]*)({[\\n\\w\\W]*?})', 'gi'), + docFrag = doc.createDocumentFragment(), + html = doc.documentElement, + head = html.firstChild, + bodyElem = doc.createElement('body'), + styleElem = doc.createElement('style'), + body; + function shim(doc) { + var a = -1; + while (++a < elemsArrLen) + // Use createElement so IE allows HTML5-named elements in a document + doc.createElement(elemsArr[a]); + } + function getCSS(styleSheetList, mediaType) { + var a = -1, + len = styleSheetList.length, + styleSheet, + cssTextArr = []; + while (++a < len) { + styleSheet = styleSheetList[a]; + // Get css from all non-screen stylesheets and their imports + if ((mediaType = styleSheet.media || mediaType) != 'screen') cssTextArr.push(getCSS(styleSheet.imports, mediaType), styleSheet.cssText); + } + return cssTextArr.join(''); + } + // Shim the document and iepp fragment + shim(doc); + shim(docFrag); + // Add iepp custom print style element + head.insertBefore(styleElem, head.firstChild); + styleElem.media = 'print'; + win.attachEvent( + 'onbeforeprint', + function() { + var a = -1, + cssText = getCSS(doc.styleSheets, 'all'), + cssTextArr = [], + rule; + body = body || doc.body; + // Get only rules which reference HTML5 elements by name + while ((rule = ruleRegExp.exec(cssText)) != null) + // Replace all html5 element references with iepp substitute classnames + cssTextArr.push((rule[1]+rule[2]+rule[3]).replace(elemRegExp, '$1.iepp_$2')+rule[4]); + // Write iepp custom print CSS + styleElem.styleSheet.cssText = cssTextArr.join('\n'); + while (++a < elemsArrLen) { + var nodeList = doc.getElementsByTagName(elemsArr[a]), + nodeListLen = nodeList.length, + b = -1; + while (++b < nodeListLen) + if (nodeList[b].className.indexOf('iepp_') < 0) + // Append iepp substitute classnames to all html5 elements + nodeList[b].className += ' iepp_'+elemsArr[a]; + } + docFrag.appendChild(body); + html.appendChild(bodyElem); + // Write iepp substitute print-safe document + bodyElem.className = body.className; + // Replace HTML5 elements with which is print-safe and shouldn't conflict since it isn't part of html5 + bodyElem.innerHTML = body.innerHTML.replace(tagRegExp, '<$1font'); + } + ); + win.attachEvent( + 'onafterprint', + function() { + // Undo everything done in onbeforeprint + bodyElem.innerHTML = ''; + html.removeChild(bodyElem); + html.appendChild(body); + styleElem.styleSheet.cssText = ''; + } + ); + })(window, document); + } + //>>END IEPP + + // Assign private properties to the return object with prefix + ret._enableHTML5 = enableHTML5; + ret._version = version; + + // Remove "no-js" class from element, if it exists: + docElement.className = docElement.className.replace(/\bno-js\b/,'') + + ' js ' + + // Add the new classes to the element. + + classes.join( ' ' ); + + return ret; + +})(this,this.document); \ No newline at end of file diff --git a/src/Test/Test/Scripts/modernizr-1.7.min.js b/src/Test/Test/Scripts/modernizr-1.7.min.js new file mode 100644 index 000000000..4b4fcc1e5 --- /dev/null +++ b/src/Test/Test/Scripts/modernizr-1.7.min.js @@ -0,0 +1,10 @@ +/*! +* Note: While Microsoft is not the author of this file, Microsoft is +* offering you a license subject to the terms of the Microsoft Software +* License Terms for Microsoft ASP.NET Model View Controller 3. +* Microsoft reserves all other rights. The notices below are provided +* for informational purposes only and are not the license terms under +* which Microsoft distributed this file. +*/ +// Modernizr v1.7 www.modernizr.com +window.Modernizr=function(a,b,c){function G(){e.input=function(a){for(var b=0,c=a.length;b7)},r.history=function(){return !!(a.history&&history.pushState)},r.draganddrop=function(){return x("dragstart")&&x("drop")},r.websockets=function(){return"WebSocket"in a},r.rgba=function(){A("background-color:rgba(150,255,150,.5)");return D(k.backgroundColor,"rgba")},r.hsla=function(){A("background-color:hsla(120,40%,100%,.5)");return D(k.backgroundColor,"rgba")||D(k.backgroundColor,"hsla")},r.multiplebgs=function(){A("background:url(//:),url(//:),red url(//:)");return(new RegExp("(url\\s*\\(.*?){3}")).test(k.background)},r.backgroundsize=function(){return F("backgroundSize")},r.borderimage=function(){return F("borderImage")},r.borderradius=function(){return F("borderRadius","",function(a){return D(a,"orderRadius")})},r.boxshadow=function(){return F("boxShadow")},r.textshadow=function(){return b.createElement("div").style.textShadow===""},r.opacity=function(){B("opacity:.55");return/^0.55$/.test(k.opacity)},r.cssanimations=function(){return F("animationName")},r.csscolumns=function(){return F("columnCount")},r.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";A((a+o.join(b+a)+o.join(c+a)).slice(0,-a.length));return D(k.backgroundImage,"gradient")},r.cssreflections=function(){return F("boxReflect")},r.csstransforms=function(){return!!E(["transformProperty","WebkitTransform","MozTransform","OTransform","msTransform"])},r.csstransforms3d=function(){var a=!!E(["perspectiveProperty","WebkitPerspective","MozPerspective","OPerspective","msPerspective"]);a&&"webkitPerspective"in g.style&&(a=w("@media ("+o.join("transform-3d),(")+"modernizr)"));return a},r.csstransitions=function(){return F("transitionProperty")},r.fontface=function(){var a,c,d=h||g,e=b.createElement("style"),f=b.implementation||{hasFeature:function(){return!1}};e.type="text/css",d.insertBefore(e,d.firstChild),a=e.sheet||e.styleSheet;var i=f.hasFeature("CSS2","")?function(b){if(!a||!b)return!1;var c=!1;try{a.insertRule(b,0),c=/src/i.test(a.cssRules[0].cssText),a.deleteRule(a.cssRules.length-1)}catch(d){}return c}:function(b){if(!a||!b)return!1;a.cssText=b;return a.cssText.length!==0&&/src/i.test(a.cssText)&&a.cssText.replace(/\r+|\n+/g,"").indexOf(b.split(" ")[0])===0};c=i('@font-face { font-family: "font"; src: url(data:,); }'),d.removeChild(e);return c},r.video=function(){var a=b.createElement("video"),c=!!a.canPlayType;if(c){c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"');var d='video/mp4; codecs="avc1.42E01E';c.h264=a.canPlayType(d+'"')||a.canPlayType(d+', mp4a.40.2"'),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"')}return c},r.audio=function(){var a=b.createElement("audio"),c=!!a.canPlayType;c&&(c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"'),c.mp3=a.canPlayType("audio/mpeg;"),c.wav=a.canPlayType('audio/wav; codecs="1"'),c.m4a=a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;"));return c},r.localstorage=function(){try{return!!localStorage.getItem}catch(a){return!1}},r.sessionstorage=function(){try{return!!sessionStorage.getItem}catch(a){return!1}},r.webWorkers=function(){return!!a.Worker},r.applicationcache=function(){return!!a.applicationCache},r.svg=function(){return!!b.createElementNS&&!!b.createElementNS(q.svg,"svg").createSVGRect},r.inlinesvg=function(){var a=b.createElement("div");a.innerHTML="";return(a.firstChild&&a.firstChild.namespaceURI)==q.svg},r.smil=function(){return!!b.createElementNS&&/SVG/.test(n.call(b.createElementNS(q.svg,"animate")))},r.svgclippaths=function(){return!!b.createElementNS&&/SVG/.test(n.call(b.createElementNS(q.svg,"clipPath")))};for(var H in r)z(r,H)&&(v=H.toLowerCase(),e[v]=r[H](),u.push((e[v]?"":"no-")+v));e.input||G(),e.crosswindowmessaging=e.postmessage,e.historymanagement=e.history,e.addTest=function(a,b){a=a.toLowerCase();if(!e[a]){b=!!b(),g.className+=" "+(b?"":"no-")+a,e[a]=b;return e}},A(""),j=l=null,f&&a.attachEvent&&function(){var a=b.createElement("div");a.innerHTML="";return a.childNodes.length!==1}()&&function(a,b){function p(a,b){var c=-1,d=a.length,e,f=[];while(++c + + + Debug + AnyCPU + + + 2.0 + {30327C08-7574-4D7E-AC95-6A58753C6855} + {E53F8FEA-EAE0-44A6-8774-FFD645390401};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Test + Test + v4.0 + false + false + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\ + TRACE + prompt + 4 + + + true + bin\ + DEBUG;TRACE + full + AnyCPU + prompt + + + + ..\packages\EntityFramework.4.1.10331.0\lib\EntityFramework.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Global.asax + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Web.config + + + Web.config + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43} + ImageProcessor.Web + + + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} + ImageProcessor + + + + + + + + + + + + + False + True + 6261 + / + + + False + False + + + False + + + + + \ No newline at end of file diff --git a/src/Test/Test/Test.vsdoc b/src/Test/Test/Test.vsdoc new file mode 100644 index 000000000..9ffff5e7f --- /dev/null +++ b/src/Test/Test/Test.vsdoc @@ -0,0 +1,7 @@ + + + + default + + + diff --git a/src/Test/Test/Views/Account/ChangePassword.cshtml b/src/Test/Test/Views/Account/ChangePassword.cshtml new file mode 100644 index 000000000..04acddf07 --- /dev/null +++ b/src/Test/Test/Views/Account/ChangePassword.cshtml @@ -0,0 +1,53 @@ +@model Test.Models.ChangePasswordModel + +@{ + ViewBag.Title = "Change Password"; +} + +

    Change Password

    +

    + Use the form below to change your password. +

    +

    + New passwords are required to be a minimum of @Membership.MinRequiredPasswordLength characters in length. +

    + + + + +@using (Html.BeginForm()) { + @Html.ValidationSummary(true, "Password change was unsuccessful. Please correct the errors and try again.") +
    +
    + Account Information + +
    + @Html.LabelFor(m => m.OldPassword) +
    +
    + @Html.PasswordFor(m => m.OldPassword) + @Html.ValidationMessageFor(m => m.OldPassword) +
    + +
    + @Html.LabelFor(m => m.NewPassword) +
    +
    + @Html.PasswordFor(m => m.NewPassword) + @Html.ValidationMessageFor(m => m.NewPassword) +
    + +
    + @Html.LabelFor(m => m.ConfirmPassword) +
    +
    + @Html.PasswordFor(m => m.ConfirmPassword) + @Html.ValidationMessageFor(m => m.ConfirmPassword) +
    + +

    + +

    +
    +
    +} diff --git a/src/Test/Test/Views/Account/ChangePasswordSuccess.cshtml b/src/Test/Test/Views/Account/ChangePasswordSuccess.cshtml new file mode 100644 index 000000000..6b6dbff63 --- /dev/null +++ b/src/Test/Test/Views/Account/ChangePasswordSuccess.cshtml @@ -0,0 +1,8 @@ +@{ + ViewBag.Title = "Change Password"; +} + +

    Change Password

    +

    + Your password has been changed successfully. +

    diff --git a/src/Test/Test/Views/Account/LogOn.cshtml b/src/Test/Test/Views/Account/LogOn.cshtml new file mode 100644 index 000000000..127bd6933 --- /dev/null +++ b/src/Test/Test/Views/Account/LogOn.cshtml @@ -0,0 +1,48 @@ +@model Test.Models.LogOnModel + +@{ + ViewBag.Title = "Log On"; +} + +

    Log On

    +

    + Please enter your user name and password. @Html.ActionLink("Register", "Register") if you don't have an account. +

    + + + + +@Html.ValidationSummary(true, "Login was unsuccessful. Please correct the errors and try again.") + +@using (Html.BeginForm()) { +
    +
    + Account Information + +
    + @Html.LabelFor(m => m.UserName) +
    +
    + @Html.TextBoxFor(m => m.UserName) + @Html.ValidationMessageFor(m => m.UserName) +
    + +
    + @Html.LabelFor(m => m.Password) +
    +
    + @Html.PasswordFor(m => m.Password) + @Html.ValidationMessageFor(m => m.Password) +
    + +
    + @Html.CheckBoxFor(m => m.RememberMe) + @Html.LabelFor(m => m.RememberMe) +
    + +

    + +

    +
    +
    +} diff --git a/src/Test/Test/Views/Account/Register.cshtml b/src/Test/Test/Views/Account/Register.cshtml new file mode 100644 index 000000000..5240b01bd --- /dev/null +++ b/src/Test/Test/Views/Account/Register.cshtml @@ -0,0 +1,61 @@ +@model Test.Models.RegisterModel + +@{ + ViewBag.Title = "Register"; +} + +

    Create a New Account

    +

    + Use the form below to create a new account. +

    +

    + Passwords are required to be a minimum of @Membership.MinRequiredPasswordLength characters in length. +

    + + + + +@using (Html.BeginForm()) { + @Html.ValidationSummary(true, "Account creation was unsuccessful. Please correct the errors and try again.") +
    +
    + Account Information + +
    + @Html.LabelFor(m => m.UserName) +
    +
    + @Html.TextBoxFor(m => m.UserName) + @Html.ValidationMessageFor(m => m.UserName) +
    + +
    + @Html.LabelFor(m => m.Email) +
    +
    + @Html.TextBoxFor(m => m.Email) + @Html.ValidationMessageFor(m => m.Email) +
    + +
    + @Html.LabelFor(m => m.Password) +
    +
    + @Html.PasswordFor(m => m.Password) + @Html.ValidationMessageFor(m => m.Password) +
    + +
    + @Html.LabelFor(m => m.ConfirmPassword) +
    +
    + @Html.PasswordFor(m => m.ConfirmPassword) + @Html.ValidationMessageFor(m => m.ConfirmPassword) +
    + +

    + +

    +
    +
    +} diff --git a/src/Test/Test/Views/Home/About.cshtml b/src/Test/Test/Views/Home/About.cshtml new file mode 100644 index 000000000..d214ffe10 --- /dev/null +++ b/src/Test/Test/Views/Home/About.cshtml @@ -0,0 +1,14 @@ +@model List +@{ + ViewBag.Title = "About Us"; +} + +

    About

    +

    + @foreach(string image in Model) + { + string path = image + "?width=150"; + + @image + } +

    diff --git a/src/Test/Test/Views/Home/Index.cshtml b/src/Test/Test/Views/Home/Index.cshtml new file mode 100644 index 000000000..f735894c2 --- /dev/null +++ b/src/Test/Test/Views/Home/Index.cshtml @@ -0,0 +1,10 @@ +@{ + ViewBag.Title = "Home Page"; +} + +

    @ViewBag.Message

    +
    +

    Test remote image

    + \ No newline at end of file diff --git a/src/Test/Test/Views/Shared/Error.cshtml b/src/Test/Test/Views/Shared/Error.cshtml new file mode 100644 index 000000000..8ee384bfd --- /dev/null +++ b/src/Test/Test/Views/Shared/Error.cshtml @@ -0,0 +1,9 @@ +@model System.Web.Mvc.HandleErrorInfo + +@{ + ViewBag.Title = "Error"; +} + +

    + Sorry, an error occurred while processing your request. +

    diff --git a/src/Test/Test/Views/Shared/_Layout.cshtml b/src/Test/Test/Views/Shared/_Layout.cshtml new file mode 100644 index 000000000..b6eb77d54 --- /dev/null +++ b/src/Test/Test/Views/Shared/_Layout.cshtml @@ -0,0 +1,33 @@ + + + + + @ViewBag.Title + + + + + +
    +
    +
    +

    My MVC Application

    +
    +
    + @Html.Partial("_LogOnPartial") +
    + +
    +
    + @RenderBody() +
    +
    +
    +
    + + diff --git a/src/Test/Test/Views/Shared/_LogOnPartial.cshtml b/src/Test/Test/Views/Shared/_LogOnPartial.cshtml new file mode 100644 index 000000000..46a854497 --- /dev/null +++ b/src/Test/Test/Views/Shared/_LogOnPartial.cshtml @@ -0,0 +1,7 @@ +@if(Request.IsAuthenticated) { + Welcome @User.Identity.Name! + [ @Html.ActionLink("Log Off", "LogOff", "Account") ] +} +else { + @:[ @Html.ActionLink("Log On", "LogOn", "Account") ] +} diff --git a/src/Test/Test/Views/Web.config b/src/Test/Test/Views/Web.config new file mode 100644 index 000000000..a4def2a3d --- /dev/null +++ b/src/Test/Test/Views/Web.config @@ -0,0 +1,58 @@ + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Test/Test/Views/_ViewStart.cshtml b/src/Test/Test/Views/_ViewStart.cshtml new file mode 100644 index 000000000..efda124b1 --- /dev/null +++ b/src/Test/Test/Views/_ViewStart.cshtml @@ -0,0 +1,3 @@ +@{ + Layout = "~/Views/Shared/_Layout.cshtml"; +} \ No newline at end of file diff --git a/src/Test/Test/Web.Debug.config b/src/Test/Test/Web.Debug.config new file mode 100644 index 000000000..2c6dd51a7 --- /dev/null +++ b/src/Test/Test/Web.Debug.config @@ -0,0 +1,30 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/Test/Test/Web.Release.config b/src/Test/Test/Web.Release.config new file mode 100644 index 000000000..4122d79bf --- /dev/null +++ b/src/Test/Test/Web.Release.config @@ -0,0 +1,31 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/Test/Test/Web.config b/src/Test/Test/Web.config new file mode 100644 index 000000000..b400b2c81 --- /dev/null +++ b/src/Test/Test/Web.config @@ -0,0 +1,117 @@ + + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Test/Test/packages.config b/src/Test/Test/packages.config new file mode 100644 index 000000000..7ab92592f --- /dev/null +++ b/src/Test/Test/packages.config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/Test/packages/EntityFramework.4.1.10331.0/EntityFramework.4.1.10331.0.nupkg.REMOVED.git-id b/src/Test/packages/EntityFramework.4.1.10331.0/EntityFramework.4.1.10331.0.nupkg.REMOVED.git-id new file mode 100644 index 000000000..e80e99351 --- /dev/null +++ b/src/Test/packages/EntityFramework.4.1.10331.0/EntityFramework.4.1.10331.0.nupkg.REMOVED.git-id @@ -0,0 +1 @@ +6c2337ee82b7b6bc2dea37bb89cff832c057bef8 \ No newline at end of file diff --git a/src/Test/packages/EntityFramework.4.1.10331.0/lib/EntityFramework.dll.REMOVED.git-id b/src/Test/packages/EntityFramework.4.1.10331.0/lib/EntityFramework.dll.REMOVED.git-id new file mode 100644 index 000000000..cf7e7c6ba --- /dev/null +++ b/src/Test/packages/EntityFramework.4.1.10331.0/lib/EntityFramework.dll.REMOVED.git-id @@ -0,0 +1 @@ +cbb615d89365c6c7b290e4ad0cc2e226df9bbb61 \ No newline at end of file diff --git a/src/Test/packages/EntityFramework.4.1.10331.0/lib/EntityFramework.xml.REMOVED.git-id b/src/Test/packages/EntityFramework.4.1.10331.0/lib/EntityFramework.xml.REMOVED.git-id new file mode 100644 index 000000000..cbeb2b222 --- /dev/null +++ b/src/Test/packages/EntityFramework.4.1.10331.0/lib/EntityFramework.xml.REMOVED.git-id @@ -0,0 +1 @@ +61abdd39cc4cb11c00715a43ad2203c3e5e97415 \ No newline at end of file diff --git a/src/Test/packages/Modernizr.1.7/Content/Scripts/modernizr-1.7.js b/src/Test/packages/Modernizr.1.7/Content/Scripts/modernizr-1.7.js new file mode 100644 index 000000000..7bc212a8c --- /dev/null +++ b/src/Test/packages/Modernizr.1.7/Content/Scripts/modernizr-1.7.js @@ -0,0 +1,969 @@ +/*! +* Note: While Microsoft is not the author of this file, Microsoft is +* offering you a license subject to the terms of the Microsoft Software +* License Terms for Microsoft ASP.NET Model View Controller 3. +* Microsoft reserves all other rights. The notices below are provided +* for informational purposes only and are not the license terms under +* which Microsoft distributed this file. +* +* Modernizr v1.7 +* http://www.modernizr.com +* +* Developed by: +* - Faruk Ates http://farukat.es/ +* - Paul Irish http://paulirish.com/ +* +* Copyright (c) 2009-2011 +*/ + + +/* + * Modernizr is a script that detects native CSS3 and HTML5 features + * available in the current UA and provides an object containing all + * features with a true/false value, depending on whether the UA has + * native support for it or not. + * + * Modernizr will also add classes to the element of the page, + * one for each feature it detects. If the UA supports it, a class + * like "cssgradients" will be added. If not, the class name will be + * "no-cssgradients". This allows for simple if-conditionals in your + * CSS, giving you fine control over the look & feel of your website. + * + * @author Faruk Ates + * @author Paul Irish + * @copyright (c) 2009-2011 Faruk Ates. + * @contributor Ben Alman + */ + +window.Modernizr = (function(window,document,undefined){ + + var version = '1.7', + + ret = {}, + + /** + * !! DEPRECATED !! + * + * enableHTML5 is a private property for advanced use only. If enabled, + * it will make Modernizr.init() run through a brief while() loop in + * which it will create all HTML5 elements in the DOM to allow for + * styling them in Internet Explorer, which does not recognize any + * non-HTML4 elements unless created in the DOM this way. + * + * enableHTML5 is ON by default. + * + * The enableHTML5 toggle option is DEPRECATED as per 1.6, and will be + * replaced in 2.0 in lieu of the modular, configurable nature of 2.0. + */ + enableHTML5 = true, + + + docElement = document.documentElement, + docHead = document.head || document.getElementsByTagName('head')[0], + + /** + * Create our "modernizr" element that we do most feature tests on. + */ + mod = 'modernizr', + modElem = document.createElement( mod ), + m_style = modElem.style, + + /** + * Create the input element for various Web Forms feature tests. + */ + inputElem = document.createElement( 'input' ), + + smile = ':)', + + tostring = Object.prototype.toString, + + // List of property values to set for css tests. See ticket #21 + prefixes = ' -webkit- -moz- -o- -ms- -khtml- '.split(' '), + + // Following spec is to expose vendor-specific style properties as: + // elem.style.WebkitBorderRadius + // and the following would be incorrect: + // elem.style.webkitBorderRadius + + // Webkit ghosts their properties in lowercase but Opera & Moz do not. + // Microsoft foregoes prefixes entirely <= IE8, but appears to + // use a lowercase `ms` instead of the correct `Ms` in IE9 + + // More here: http://github.com/Modernizr/Modernizr/issues/issue/21 + domPrefixes = 'Webkit Moz O ms Khtml'.split(' '), + + ns = {'svg': 'http://www.w3.org/2000/svg'}, + + tests = {}, + inputs = {}, + attrs = {}, + + classes = [], + + featurename, // used in testing loop + + + + // todo: consider using http://javascript.nwbox.com/CSSSupport/css-support.js instead + testMediaQuery = function(mq){ + + var st = document.createElement('style'), + div = document.createElement('div'), + ret; + + st.textContent = mq + '{#modernizr{height:3px}}'; + docHead.appendChild(st); + div.id = 'modernizr'; + docElement.appendChild(div); + + ret = div.offsetHeight === 3; + + st.parentNode.removeChild(st); + div.parentNode.removeChild(div); + + return !!ret; + + }, + + + /** + * isEventSupported determines if a given element supports the given event + * function from http://yura.thinkweb2.com/isEventSupported/ + */ + isEventSupported = (function(){ + + var TAGNAMES = { + 'select':'input','change':'input', + 'submit':'form','reset':'form', + 'error':'img','load':'img','abort':'img' + }; + + function isEventSupported(eventName, element) { + + element = element || document.createElement(TAGNAMES[eventName] || 'div'); + eventName = 'on' + eventName; + + // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those + var isSupported = (eventName in element); + + if (!isSupported) { + // If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element + if (!element.setAttribute) { + element = document.createElement('div'); + } + if (element.setAttribute && element.removeAttribute) { + element.setAttribute(eventName, ''); + isSupported = is(element[eventName], 'function'); + + // If property was created, "remove it" (by setting value to `undefined`) + if (!is(element[eventName], undefined)) { + element[eventName] = undefined; + } + element.removeAttribute(eventName); + } + } + + element = null; + return isSupported; + } + return isEventSupported; + })(); + + + // hasOwnProperty shim by kangax needed for Safari 2.0 support + var _hasOwnProperty = ({}).hasOwnProperty, hasOwnProperty; + if (!is(_hasOwnProperty, undefined) && !is(_hasOwnProperty.call, undefined)) { + hasOwnProperty = function (object, property) { + return _hasOwnProperty.call(object, property); + }; + } + else { + hasOwnProperty = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */ + return ((property in object) && is(object.constructor.prototype[property], undefined)); + }; + } + + /** + * set_css applies given styles to the Modernizr DOM node. + */ + function set_css( str ) { + m_style.cssText = str; + } + + /** + * set_css_all extrapolates all vendor-specific css strings. + */ + function set_css_all( str1, str2 ) { + return set_css(prefixes.join(str1 + ';') + ( str2 || '' )); + } + + /** + * is returns a boolean for if typeof obj is exactly type. + */ + function is( obj, type ) { + return typeof obj === type; + } + + /** + * contains returns a boolean for if substr is found within str. + */ + function contains( str, substr ) { + return (''+str).indexOf( substr ) !== -1; + } + + /** + * test_props is a generic CSS / DOM property test; if a browser supports + * a certain property, it won't return undefined for it. + * A supported CSS property returns empty string when its not yet set. + */ + function test_props( props, callback ) { + for ( var i in props ) { + if ( m_style[ props[i] ] !== undefined && ( !callback || callback( props[i], modElem ) ) ) { + return true; + } + } + } + + /** + * test_props_all tests a list of DOM properties we want to check against. + * We specify literally ALL possible (known and/or likely) properties on + * the element including the non-vendor prefixed one, for forward- + * compatibility. + */ + function test_props_all( prop, callback ) { + + var uc_prop = prop.charAt(0).toUpperCase() + prop.substr(1), + props = (prop + ' ' + domPrefixes.join(uc_prop + ' ') + uc_prop).split(' '); + + return !!test_props( props, callback ); + } + + + /** + * Tests + * ----- + */ + + tests['flexbox'] = function() { + /** + * set_prefixed_value_css sets the property of a specified element + * adding vendor prefixes to the VALUE of the property. + * @param {Element} element + * @param {string} property The property name. This will not be prefixed. + * @param {string} value The value of the property. This WILL be prefixed. + * @param {string=} extra Additional CSS to append unmodified to the end of + * the CSS string. + */ + function set_prefixed_value_css(element, property, value, extra) { + property += ':'; + element.style.cssText = (property + prefixes.join(value + ';' + property)).slice(0, -property.length) + (extra || ''); + } + + /** + * set_prefixed_property_css sets the property of a specified element + * adding vendor prefixes to the NAME of the property. + * @param {Element} element + * @param {string} property The property name. This WILL be prefixed. + * @param {string} value The value of the property. This will not be prefixed. + * @param {string=} extra Additional CSS to append unmodified to the end of + * the CSS string. + */ + function set_prefixed_property_css(element, property, value, extra) { + element.style.cssText = prefixes.join(property + ':' + value + ';') + (extra || ''); + } + + var c = document.createElement('div'), + elem = document.createElement('div'); + + set_prefixed_value_css(c, 'display', 'box', 'width:42px;padding:0;'); + set_prefixed_property_css(elem, 'box-flex', '1', 'width:10px;'); + + c.appendChild(elem); + docElement.appendChild(c); + + var ret = elem.offsetWidth === 42; + + c.removeChild(elem); + docElement.removeChild(c); + + return ret; + }; + + // On the S60 and BB Storm, getContext exists, but always returns undefined + // http://github.com/Modernizr/Modernizr/issues/issue/97/ + + tests['canvas'] = function() { + var elem = document.createElement( 'canvas' ); + return !!(elem.getContext && elem.getContext('2d')); + }; + + tests['canvastext'] = function() { + return !!(ret['canvas'] && is(document.createElement( 'canvas' ).getContext('2d').fillText, 'function')); + }; + + // This WebGL test false positives in FF depending on graphics hardware. But really it's quite impossible to know + // wether webgl will succeed until after you create the context. You might have hardware that can support + // a 100x100 webgl canvas, but will not support a 1000x1000 webgl canvas. So this feature inference is weak, + // but intentionally so. + tests['webgl'] = function(){ + return !!window.WebGLRenderingContext; + }; + + /* + * The Modernizr.touch test only indicates if the browser supports + * touch events, which does not necessarily reflect a touchscreen + * device, as evidenced by tablets running Windows 7 or, alas, + * the Palm Pre / WebOS (touch) phones. + * + * Additionally, Chrome (desktop) used to lie about its support on this, + * but that has since been rectified: http://crbug.com/36415 + * + * We also test for Firefox 4 Multitouch Support. + * + * For more info, see: http://modernizr.github.com/Modernizr/touch.html + */ + + tests['touch'] = function() { + + return ('ontouchstart' in window) || testMediaQuery('@media ('+prefixes.join('touch-enabled),(')+'modernizr)'); + + }; + + + /** + * geolocation tests for the new Geolocation API specification. + * This test is a standards compliant-only test; for more complete + * testing, including a Google Gears fallback, please see: + * http://code.google.com/p/geo-location-javascript/ + * or view a fallback solution using google's geo API: + * http://gist.github.com/366184 + */ + tests['geolocation'] = function() { + return !!navigator.geolocation; + }; + + // Per 1.6: + // This used to be Modernizr.crosswindowmessaging but the longer + // name has been deprecated in favor of a shorter and property-matching one. + // The old API is still available in 1.6, but as of 2.0 will throw a warning, + // and in the first release thereafter disappear entirely. + tests['postmessage'] = function() { + return !!window.postMessage; + }; + + // Web SQL database detection is tricky: + + // In chrome incognito mode, openDatabase is truthy, but using it will + // throw an exception: http://crbug.com/42380 + // We can create a dummy database, but there is no way to delete it afterwards. + + // Meanwhile, Safari users can get prompted on any database creation. + // If they do, any page with Modernizr will give them a prompt: + // http://github.com/Modernizr/Modernizr/issues/closed#issue/113 + + // We have chosen to allow the Chrome incognito false positive, so that Modernizr + // doesn't litter the web with these test databases. As a developer, you'll have + // to account for this gotcha yourself. + tests['websqldatabase'] = function() { + var result = !!window.openDatabase; + /* if (result){ + try { + result = !!openDatabase( mod + "testdb", "1.0", mod + "testdb", 2e4); + } catch(e) { + } + } */ + return result; + }; + + // Vendors have inconsistent prefixing with the experimental Indexed DB: + // - Firefox is shipping indexedDB in FF4 as moz_indexedDB + // - Webkit's implementation is accessible through webkitIndexedDB + // We test both styles. + tests['indexedDB'] = function(){ + for (var i = -1, len = domPrefixes.length; ++i < len; ){ + var prefix = domPrefixes[i].toLowerCase(); + if (window[prefix + '_indexedDB'] || window[prefix + 'IndexedDB']){ + return true; + } + } + return false; + }; + + // documentMode logic from YUI to filter out IE8 Compat Mode + // which false positives. + tests['hashchange'] = function() { + return isEventSupported('hashchange', window) && ( document.documentMode === undefined || document.documentMode > 7 ); + }; + + // Per 1.6: + // This used to be Modernizr.historymanagement but the longer + // name has been deprecated in favor of a shorter and property-matching one. + // The old API is still available in 1.6, but as of 2.0 will throw a warning, + // and in the first release thereafter disappear entirely. + tests['history'] = function() { + return !!(window.history && history.pushState); + }; + + tests['draganddrop'] = function() { + return isEventSupported('dragstart') && isEventSupported('drop'); + }; + + tests['websockets'] = function(){ + return ('WebSocket' in window); + }; + + + // http://css-tricks.com/rgba-browser-support/ + tests['rgba'] = function() { + // Set an rgba() color and check the returned value + + set_css( 'background-color:rgba(150,255,150,.5)' ); + + return contains( m_style.backgroundColor, 'rgba' ); + }; + + tests['hsla'] = function() { + // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally, + // except IE9 who retains it as hsla + + set_css('background-color:hsla(120,40%,100%,.5)' ); + + return contains( m_style.backgroundColor, 'rgba' ) || contains( m_style.backgroundColor, 'hsla' ); + }; + + tests['multiplebgs'] = function() { + // Setting multiple images AND a color on the background shorthand property + // and then querying the style.background property value for the number of + // occurrences of "url(" is a reliable method for detecting ACTUAL support for this! + + set_css( 'background:url(//:),url(//:),red url(//:)' ); + + // If the UA supports multiple backgrounds, there should be three occurrences + // of the string "url(" in the return value for elem_style.background + + return new RegExp("(url\\s*\\(.*?){3}").test(m_style.background); + }; + + + // In testing support for a given CSS property, it's legit to test: + // `elem.style[styleName] !== undefined` + // If the property is supported it will return an empty string, + // if unsupported it will return undefined. + + // We'll take advantage of this quick test and skip setting a style + // on our modernizr element, but instead just testing undefined vs + // empty string. + + + tests['backgroundsize'] = function() { + return test_props_all( 'backgroundSize' ); + }; + + tests['borderimage'] = function() { + return test_props_all( 'borderImage' ); + }; + + + // Super comprehensive table about all the unique implementations of + // border-radius: http://muddledramblings.com/table-of-css3-border-radius-compliance + + tests['borderradius'] = function() { + return test_props_all( 'borderRadius', '', function( prop ) { + return contains( prop, 'orderRadius' ); + }); + }; + + // WebOS unfortunately false positives on this test. + tests['boxshadow'] = function() { + return test_props_all( 'boxShadow' ); + }; + + // FF3.0 will false positive on this test + tests['textshadow'] = function(){ + return document.createElement('div').style.textShadow === ''; + }; + + + tests['opacity'] = function() { + // Browsers that actually have CSS Opacity implemented have done so + // according to spec, which means their return values are within the + // range of [0.0,1.0] - including the leading zero. + + set_css_all( 'opacity:.55' ); + + // The non-literal . in this regex is intentional: + // German Chrome returns this value as 0,55 + // https://github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632 + return /^0.55$/.test(m_style.opacity); + }; + + + tests['cssanimations'] = function() { + return test_props_all( 'animationName' ); + }; + + + tests['csscolumns'] = function() { + return test_props_all( 'columnCount' ); + }; + + + tests['cssgradients'] = function() { + /** + * For CSS Gradients syntax, please see: + * http://webkit.org/blog/175/introducing-css-gradients/ + * https://developer.mozilla.org/en/CSS/-moz-linear-gradient + * https://developer.mozilla.org/en/CSS/-moz-radial-gradient + * http://dev.w3.org/csswg/css3-images/#gradients- + */ + + var str1 = 'background-image:', + str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));', + str3 = 'linear-gradient(left top,#9f9, white);'; + + set_css( + (str1 + prefixes.join(str2 + str1) + prefixes.join(str3 + str1)).slice(0,-str1.length) + ); + + return contains( m_style.backgroundImage, 'gradient' ); + }; + + + tests['cssreflections'] = function() { + return test_props_all( 'boxReflect' ); + }; + + + tests['csstransforms'] = function() { + return !!test_props([ 'transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform' ]); + }; + + + tests['csstransforms3d'] = function() { + + var ret = !!test_props([ 'perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective' ]); + + // Webkit’s 3D transforms are passed off to the browser's own graphics renderer. + // It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in + // some conditions. As a result, Webkit typically recognizes the syntax but + // will sometimes throw a false positive, thus we must do a more thorough check: + if (ret && 'webkitPerspective' in docElement.style){ + + // Webkit allows this media query to succeed only if the feature is enabled. + // `@media (transform-3d),(-o-transform-3d),(-moz-transform-3d),(-ms-transform-3d),(-webkit-transform-3d),(modernizr){ ... }` + ret = testMediaQuery('@media ('+prefixes.join('transform-3d),(')+'modernizr)'); + } + return ret; + }; + + + tests['csstransitions'] = function() { + return test_props_all( 'transitionProperty' ); + }; + + + // @font-face detection routine by Diego Perini + // http://javascript.nwbox.com/CSSSupport/ + tests['fontface'] = function(){ + + var + sheet, bool, + head = docHead || docElement, + style = document.createElement("style"), + impl = document.implementation || { hasFeature: function() { return false; } }; + + style.type = 'text/css'; + head.insertBefore(style, head.firstChild); + sheet = style.sheet || style.styleSheet; + + var supportAtRule = impl.hasFeature('CSS2', '') ? + function(rule) { + if (!(sheet && rule)) return false; + var result = false; + try { + sheet.insertRule(rule, 0); + result = (/src/i).test(sheet.cssRules[0].cssText); + sheet.deleteRule(sheet.cssRules.length - 1); + } catch(e) { } + return result; + } : + function(rule) { + if (!(sheet && rule)) return false; + sheet.cssText = rule; + + return sheet.cssText.length !== 0 && (/src/i).test(sheet.cssText) && + sheet.cssText + .replace(/\r+|\n+/g, '') + .indexOf(rule.split(' ')[0]) === 0; + }; + + bool = supportAtRule('@font-face { font-family: "font"; src: url(data:,); }'); + head.removeChild(style); + return bool; + }; + + + // These tests evaluate support of the video/audio elements, as well as + // testing what types of content they support. + // + // We're using the Boolean constructor here, so that we can extend the value + // e.g. Modernizr.video // true + // Modernizr.video.ogg // 'probably' + // + // Codec values from : http://github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845 + // thx to NielsLeenheer and zcorpan + + // Note: in FF 3.5.1 and 3.5.0, "no" was a return value instead of empty string. + // Modernizr does not normalize for that. + + tests['video'] = function() { + var elem = document.createElement('video'), + bool = !!elem.canPlayType; + + if (bool){ + bool = new Boolean(bool); + bool.ogg = elem.canPlayType('video/ogg; codecs="theora"'); + + // Workaround required for IE9, which doesn't report video support without audio codec specified. + // bug 599718 @ msft connect + var h264 = 'video/mp4; codecs="avc1.42E01E'; + bool.h264 = elem.canPlayType(h264 + '"') || elem.canPlayType(h264 + ', mp4a.40.2"'); + + bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"'); + } + return bool; + }; + + tests['audio'] = function() { + var elem = document.createElement('audio'), + bool = !!elem.canPlayType; + + if (bool){ + bool = new Boolean(bool); + bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"'); + bool.mp3 = elem.canPlayType('audio/mpeg;'); + + // Mimetypes accepted: + // https://developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements + // http://bit.ly/iphoneoscodecs + bool.wav = elem.canPlayType('audio/wav; codecs="1"'); + bool.m4a = elem.canPlayType('audio/x-m4a;') || elem.canPlayType('audio/aac;'); + } + return bool; + }; + + + // Firefox has made these tests rather unfun. + + // In FF4, if disabled, window.localStorage should === null. + + // Normally, we could not test that directly and need to do a + // `('localStorage' in window) && ` test first because otherwise Firefox will + // throw http://bugzil.la/365772 if cookies are disabled + + // However, in Firefox 4 betas, if dom.storage.enabled == false, just mentioning + // the property will throw an exception. http://bugzil.la/599479 + // This looks to be fixed for FF4 Final. + + // Because we are forced to try/catch this, we'll go aggressive. + + // FWIW: IE8 Compat mode supports these features completely: + // http://www.quirksmode.org/dom/html5.html + // But IE8 doesn't support either with local files + + tests['localstorage'] = function() { + try { + return !!localStorage.getItem; + } catch(e) { + return false; + } + }; + + tests['sessionstorage'] = function() { + try { + return !!sessionStorage.getItem; + } catch(e){ + return false; + } + }; + + + tests['webWorkers'] = function () { + return !!window.Worker; + }; + + + tests['applicationcache'] = function() { + return !!window.applicationCache; + }; + + + // Thanks to Erik Dahlstrom + tests['svg'] = function(){ + return !!document.createElementNS && !!document.createElementNS(ns.svg, "svg").createSVGRect; + }; + + tests['inlinesvg'] = function() { + var div = document.createElement('div'); + div.innerHTML = ''; + return (div.firstChild && div.firstChild.namespaceURI) == ns.svg; + }; + + // Thanks to F1lt3r and lucideer + // http://github.com/Modernizr/Modernizr/issues#issue/35 + tests['smil'] = function(){ + return !!document.createElementNS && /SVG/.test(tostring.call(document.createElementNS(ns.svg,'animate'))); + }; + + tests['svgclippaths'] = function(){ + // Possibly returns a false positive in Safari 3.2? + return !!document.createElementNS && /SVG/.test(tostring.call(document.createElementNS(ns.svg,'clipPath'))); + }; + + + // input features and input types go directly onto the ret object, bypassing the tests loop. + // Hold this guy to execute in a moment. + function webforms(){ + + // Run through HTML5's new input attributes to see if the UA understands any. + // We're using f which is the element created early on + // Mike Taylr has created a comprehensive resource for testing these attributes + // when applied to all input types: + // http://miketaylr.com/code/input-type-attr.html + // spec: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary + ret['input'] = (function(props) { + for (var i = 0, len = props.length; i>BEGIN IEPP + // Enable HTML 5 elements for styling in IE. + // fyi: jscript version does not reflect trident version + // therefore ie9 in ie7 mode will still have a jScript v.9 + if ( enableHTML5 && window.attachEvent && (function(){ var elem = document.createElement("div"); + elem.innerHTML = ""; + return elem.childNodes.length !== 1; })()) { + // iepp v1.6.2 by @jon_neal : code.google.com/p/ie-print-protector + (function(win, doc) { + var elems = 'abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video', + elemsArr = elems.split('|'), + elemsArrLen = elemsArr.length, + elemRegExp = new RegExp('(^|\\s)('+elems+')', 'gi'), + tagRegExp = new RegExp('<(\/*)('+elems+')', 'gi'), + ruleRegExp = new RegExp('(^|[^\\n]*?\\s)('+elems+')([^\\n]*)({[\\n\\w\\W]*?})', 'gi'), + docFrag = doc.createDocumentFragment(), + html = doc.documentElement, + head = html.firstChild, + bodyElem = doc.createElement('body'), + styleElem = doc.createElement('style'), + body; + function shim(doc) { + var a = -1; + while (++a < elemsArrLen) + // Use createElement so IE allows HTML5-named elements in a document + doc.createElement(elemsArr[a]); + } + function getCSS(styleSheetList, mediaType) { + var a = -1, + len = styleSheetList.length, + styleSheet, + cssTextArr = []; + while (++a < len) { + styleSheet = styleSheetList[a]; + // Get css from all non-screen stylesheets and their imports + if ((mediaType = styleSheet.media || mediaType) != 'screen') cssTextArr.push(getCSS(styleSheet.imports, mediaType), styleSheet.cssText); + } + return cssTextArr.join(''); + } + // Shim the document and iepp fragment + shim(doc); + shim(docFrag); + // Add iepp custom print style element + head.insertBefore(styleElem, head.firstChild); + styleElem.media = 'print'; + win.attachEvent( + 'onbeforeprint', + function() { + var a = -1, + cssText = getCSS(doc.styleSheets, 'all'), + cssTextArr = [], + rule; + body = body || doc.body; + // Get only rules which reference HTML5 elements by name + while ((rule = ruleRegExp.exec(cssText)) != null) + // Replace all html5 element references with iepp substitute classnames + cssTextArr.push((rule[1]+rule[2]+rule[3]).replace(elemRegExp, '$1.iepp_$2')+rule[4]); + // Write iepp custom print CSS + styleElem.styleSheet.cssText = cssTextArr.join('\n'); + while (++a < elemsArrLen) { + var nodeList = doc.getElementsByTagName(elemsArr[a]), + nodeListLen = nodeList.length, + b = -1; + while (++b < nodeListLen) + if (nodeList[b].className.indexOf('iepp_') < 0) + // Append iepp substitute classnames to all html5 elements + nodeList[b].className += ' iepp_'+elemsArr[a]; + } + docFrag.appendChild(body); + html.appendChild(bodyElem); + // Write iepp substitute print-safe document + bodyElem.className = body.className; + // Replace HTML5 elements with which is print-safe and shouldn't conflict since it isn't part of html5 + bodyElem.innerHTML = body.innerHTML.replace(tagRegExp, '<$1font'); + } + ); + win.attachEvent( + 'onafterprint', + function() { + // Undo everything done in onbeforeprint + bodyElem.innerHTML = ''; + html.removeChild(bodyElem); + html.appendChild(body); + styleElem.styleSheet.cssText = ''; + } + ); + })(window, document); + } + //>>END IEPP + + // Assign private properties to the return object with prefix + ret._enableHTML5 = enableHTML5; + ret._version = version; + + // Remove "no-js" class from element, if it exists: + docElement.className = docElement.className.replace(/\bno-js\b/,'') + + ' js ' + + // Add the new classes to the element. + + classes.join( ' ' ); + + return ret; + +})(this,this.document); \ No newline at end of file diff --git a/src/Test/packages/Modernizr.1.7/Content/Scripts/modernizr-1.7.min.js b/src/Test/packages/Modernizr.1.7/Content/Scripts/modernizr-1.7.min.js new file mode 100644 index 000000000..4b4fcc1e5 --- /dev/null +++ b/src/Test/packages/Modernizr.1.7/Content/Scripts/modernizr-1.7.min.js @@ -0,0 +1,10 @@ +/*! +* Note: While Microsoft is not the author of this file, Microsoft is +* offering you a license subject to the terms of the Microsoft Software +* License Terms for Microsoft ASP.NET Model View Controller 3. +* Microsoft reserves all other rights. The notices below are provided +* for informational purposes only and are not the license terms under +* which Microsoft distributed this file. +*/ +// Modernizr v1.7 www.modernizr.com +window.Modernizr=function(a,b,c){function G(){e.input=function(a){for(var b=0,c=a.length;b7)},r.history=function(){return !!(a.history&&history.pushState)},r.draganddrop=function(){return x("dragstart")&&x("drop")},r.websockets=function(){return"WebSocket"in a},r.rgba=function(){A("background-color:rgba(150,255,150,.5)");return D(k.backgroundColor,"rgba")},r.hsla=function(){A("background-color:hsla(120,40%,100%,.5)");return D(k.backgroundColor,"rgba")||D(k.backgroundColor,"hsla")},r.multiplebgs=function(){A("background:url(//:),url(//:),red url(//:)");return(new RegExp("(url\\s*\\(.*?){3}")).test(k.background)},r.backgroundsize=function(){return F("backgroundSize")},r.borderimage=function(){return F("borderImage")},r.borderradius=function(){return F("borderRadius","",function(a){return D(a,"orderRadius")})},r.boxshadow=function(){return F("boxShadow")},r.textshadow=function(){return b.createElement("div").style.textShadow===""},r.opacity=function(){B("opacity:.55");return/^0.55$/.test(k.opacity)},r.cssanimations=function(){return F("animationName")},r.csscolumns=function(){return F("columnCount")},r.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";A((a+o.join(b+a)+o.join(c+a)).slice(0,-a.length));return D(k.backgroundImage,"gradient")},r.cssreflections=function(){return F("boxReflect")},r.csstransforms=function(){return!!E(["transformProperty","WebkitTransform","MozTransform","OTransform","msTransform"])},r.csstransforms3d=function(){var a=!!E(["perspectiveProperty","WebkitPerspective","MozPerspective","OPerspective","msPerspective"]);a&&"webkitPerspective"in g.style&&(a=w("@media ("+o.join("transform-3d),(")+"modernizr)"));return a},r.csstransitions=function(){return F("transitionProperty")},r.fontface=function(){var a,c,d=h||g,e=b.createElement("style"),f=b.implementation||{hasFeature:function(){return!1}};e.type="text/css",d.insertBefore(e,d.firstChild),a=e.sheet||e.styleSheet;var i=f.hasFeature("CSS2","")?function(b){if(!a||!b)return!1;var c=!1;try{a.insertRule(b,0),c=/src/i.test(a.cssRules[0].cssText),a.deleteRule(a.cssRules.length-1)}catch(d){}return c}:function(b){if(!a||!b)return!1;a.cssText=b;return a.cssText.length!==0&&/src/i.test(a.cssText)&&a.cssText.replace(/\r+|\n+/g,"").indexOf(b.split(" ")[0])===0};c=i('@font-face { font-family: "font"; src: url(data:,); }'),d.removeChild(e);return c},r.video=function(){var a=b.createElement("video"),c=!!a.canPlayType;if(c){c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"');var d='video/mp4; codecs="avc1.42E01E';c.h264=a.canPlayType(d+'"')||a.canPlayType(d+', mp4a.40.2"'),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"')}return c},r.audio=function(){var a=b.createElement("audio"),c=!!a.canPlayType;c&&(c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"'),c.mp3=a.canPlayType("audio/mpeg;"),c.wav=a.canPlayType('audio/wav; codecs="1"'),c.m4a=a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;"));return c},r.localstorage=function(){try{return!!localStorage.getItem}catch(a){return!1}},r.sessionstorage=function(){try{return!!sessionStorage.getItem}catch(a){return!1}},r.webWorkers=function(){return!!a.Worker},r.applicationcache=function(){return!!a.applicationCache},r.svg=function(){return!!b.createElementNS&&!!b.createElementNS(q.svg,"svg").createSVGRect},r.inlinesvg=function(){var a=b.createElement("div");a.innerHTML="";return(a.firstChild&&a.firstChild.namespaceURI)==q.svg},r.smil=function(){return!!b.createElementNS&&/SVG/.test(n.call(b.createElementNS(q.svg,"animate")))},r.svgclippaths=function(){return!!b.createElementNS&&/SVG/.test(n.call(b.createElementNS(q.svg,"clipPath")))};for(var H in r)z(r,H)&&(v=H.toLowerCase(),e[v]=r[H](),u.push((e[v]?"":"no-")+v));e.input||G(),e.crosswindowmessaging=e.postmessage,e.historymanagement=e.history,e.addTest=function(a,b){a=a.toLowerCase();if(!e[a]){b=!!b(),g.className+=" "+(b?"":"no-")+a,e[a]=b;return e}},A(""),j=l=null,f&&a.attachEvent&&function(){var a=b.createElement("div");a.innerHTML="";return a.childNodes.length!==1}()&&function(a,b){function p(a,b){var c=-1,d=a.length,e,f=[]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

    v(#I+E$zvvQCNcbgTvU>6 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 YH)Gd&j2%Zd8wcNy;KaU7ZoQ29FL={RuK)l5 literal 0 HcmV?d00001 diff --git a/src/Test/packages/jQuery.1.5.1/Content/Scripts/jquery-1.5.1.js.REMOVED.git-id b/src/Test/packages/jQuery.1.5.1/Content/Scripts/jquery-1.5.1.js.REMOVED.git-id new file mode 100644 index 000000000..25bdfee81 --- /dev/null +++ b/src/Test/packages/jQuery.1.5.1/Content/Scripts/jquery-1.5.1.js.REMOVED.git-id @@ -0,0 +1 @@ +5948d8cc4932a48bc126343cf1d5ea2ac5f0b3c0 \ No newline at end of file diff --git a/src/Test/packages/jQuery.1.5.1/Content/Scripts/jquery-1.5.1.min.js.REMOVED.git-id b/src/Test/packages/jQuery.1.5.1/Content/Scripts/jquery-1.5.1.min.js.REMOVED.git-id new file mode 100644 index 000000000..1013447da --- /dev/null +++ b/src/Test/packages/jQuery.1.5.1/Content/Scripts/jquery-1.5.1.min.js.REMOVED.git-id @@ -0,0 +1 @@ +eec584bc589cf1ab1fe50781c1780f89c90aa31b \ No newline at end of file diff --git a/src/Test/packages/jQuery.1.5.1/jQuery.1.5.1.nupkg.REMOVED.git-id b/src/Test/packages/jQuery.1.5.1/jQuery.1.5.1.nupkg.REMOVED.git-id new file mode 100644 index 000000000..e184a83d0 --- /dev/null +++ b/src/Test/packages/jQuery.1.5.1/jQuery.1.5.1.nupkg.REMOVED.git-id @@ -0,0 +1 @@ +10542650ebb596cd1cfef53bf8fd64b86ee5f957 \ No newline at end of file diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png new file mode 100644 index 0000000000000000000000000000000000000000..5b5dab2ab7b1c50dea9cfe73dc5a269a92d2d4b4 GIT binary patch literal 180 zcmeAS@N?(olHy`uVBq!ia0vp^8bF-F!3HG1q!d*FscKIb$B>N1x91EQ4=4yQ7#`R^ z$vje}bP0l+XkK DSH>_4 literal 0 HcmV?d00001 diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_flat_75_ffffff_40x100.png b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_flat_75_ffffff_40x100.png new file mode 100644 index 0000000000000000000000000000000000000000..ac8b229af950c29356abf64a6c4aa894575445f0 GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^8bF-F!3HG1q!d*FsY*{5$B>N1x91EQ4=4yQYz+E8 zPo9&<{J;c_6SHRil>2s{Zw^OT)6@jj2u|u!(plXsM>LJD`vD!n;OXk;vd$@?2>^GI BH@yG= literal 0 HcmV?d00001 diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..ad3d6346e00f246102f72f2e026ed0491988b394 GIT binary patch literal 120 zcmeAS@N?(olHy`uVBq!ia0vp^j6gJjgAK^akKnour0hLi978O6-<~(*I$*%ybaDOn z{W;e!B}_MSUQoPXhYd^Y6RUoS1yepnPx`2Kz)7OXQG!!=-jY=F+d2OOy?#DnJ32>z UEim$g7SJdLPgg&ebxsLQ09~*s;{X5v literal 0 HcmV?d00001 diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_glass_65_ffffff_1x400.png b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..42ccba269b6e91bef12ad0fa18be651b5ef0ee68 GIT binary patch literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^j6gJjgAK^akKnouqzpV=978O6-=0?FV^9z|eBtf= z|7WztIJ;WT>{+tN>ySr~=F{k$>;_x^_y?afmf9pRKH0)6?eSP?3s5hEr>mdKI;Vst E0O;M1& literal 0 HcmV?d00001 diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_glass_75_dadada_1x400.png b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_glass_75_dadada_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..5a46b47cb16631068aee9e0bd61269fc4e95e5cd GIT binary patch literal 111 zcmeAS@N?(olHy`uVBq!ia0vp^j6gJjgAK^akKnouq|7{B978O6lPf+wIa#m9#>Unb zm^4K~wN3Zq+uP{vDV26o)#~38k_!`W=^oo1w6ixmPC4R1b Tyd6G3lNdZ*{an^LB{Ts5`idse literal 0 HcmV?d00001 diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png new file mode 100644 index 0000000000000000000000000000000000000000..7c9fa6c6edcfcdd3e5b77e6f547b719e6fc66e30 GIT binary patch literal 101 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 literal 0 HcmV?d00001 diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-icons_2e83ff_256x240.png b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-icons_2e83ff_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..45e8928e5284adacea3f9ec07b9b50667d2ac65f GIT binary patch literal 4369 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 literal 0 HcmV?d00001 diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-icons_454545_256x240.png b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-icons_454545_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..7ec70d11bfb2f77374dfd00ef61ba0c3647b5a0c GIT binary patch literal 4369 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 k*Kv;w;*%(i9W@fAqs5i2wiq literal 0 HcmV?d00001 diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-icons_888888_256x240.png b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/images/ui-icons_888888_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..5ba708c39172a69e069136bd1309c4322c61f571 GIT binary patch literal 4369 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 literal 0 HcmV?d00001 diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.accordion.css b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.accordion.css new file mode 100644 index 000000000..4a67cbf8e --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.accordion.css @@ -0,0 +1,24 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Accordion 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Accordion#theming + */ +/* IE/Win - Fix animation bug - #4615 */ +.ui-accordion { width: 100%; } +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } +.ui-accordion .ui-accordion-li-fix { display: inline; } +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } +.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } +.ui-accordion .ui-accordion-content-active { display: block; } diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.all.css b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.all.css new file mode 100644 index 000000000..2b2c103e8 --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.all.css @@ -0,0 +1,16 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI CSS Framework 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Theming + */ +@import "jquery.ui.base.css"; +@import "jquery.ui.theme.css"; diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.autocomplete.css b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.autocomplete.css new file mode 100644 index 000000000..aac4e204d --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.autocomplete.css @@ -0,0 +1,62 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Autocomplete 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * http://docs.jquery.com/UI/Autocomplete#theming + */ +.ui-autocomplete { position: absolute; cursor: default; } + +/* workarounds */ +* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ + +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Menu 1.8.11 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Menu#theming + */ +.ui-menu { + list-style:none; + padding: 2px; + margin: 0; + display:block; + float: left; +} +.ui-menu .ui-menu { + margin-top: -3px; +} +.ui-menu .ui-menu-item { + margin:0; + padding: 0; + zoom: 1; + float: left; + clear: left; + width: 100%; +} +.ui-menu .ui-menu-item a { + text-decoration:none; + display:block; + padding:.2em .4em; + line-height:1.5; + zoom:1; +} +.ui-menu .ui-menu-item a.ui-state-hover, +.ui-menu .ui-menu-item a.ui-state-active { + font-weight: normal; + margin: -1px; +} diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.base.css b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.base.css new file mode 100644 index 000000000..f52ee39b9 --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.base.css @@ -0,0 +1,11 @@ +@import url("jquery.ui.core.css"); +@import url("jquery.ui.resizable.css"); +@import url("jquery.ui.selectable.css"); +@import url("jquery.ui.accordion.css"); +@import url("jquery.ui.autocomplete.css"); +@import url("jquery.ui.button.css"); +@import url("jquery.ui.dialog.css"); +@import url("jquery.ui.slider.css"); +@import url("jquery.ui.tabs.css"); +@import url("jquery.ui.datepicker.css"); +@import url("jquery.ui.progressbar.css"); \ No newline at end of file diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.button.css b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.button.css new file mode 100644 index 000000000..af6c985b8 --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.button.css @@ -0,0 +1,43 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Button 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Button#theming + */ +.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ +.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ +button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ +.ui-button-icons-only { width: 3.4em; } +button.ui-button-icons-only { width: 3.7em; } + +/*button text element */ +.ui-button .ui-button-text { display: block; line-height: 1.4; } +.ui-button-text-only .ui-button-text { padding: .4em 1em; } +.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } +.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } +.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } +.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } +/* no icon support for input elements, provide padding by default */ +input.ui-button { padding: .4em 1em; } + +/*button icon element(s) */ +.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } +.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } +.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } +.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } +.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } + +/*button sets*/ +.ui-buttonset { margin-right: 7px; } +.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } + +/* workarounds */ +button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.core.css b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.core.css new file mode 100644 index 000000000..55fb8b0d9 --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.core.css @@ -0,0 +1,46 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI CSS Framework 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Theming/API + */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.datepicker.css b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.datepicker.css new file mode 100644 index 000000000..7126923cc --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.datepicker.css @@ -0,0 +1,73 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Datepicker 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Datepicker#theming + */ +.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + display: none; /*sorry for IE5*/ + display/**/: block; /*sorry for IE5*/ + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +} \ No newline at end of file diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.dialog.css b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.dialog.css new file mode 100644 index 000000000..311dd32e5 --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.dialog.css @@ -0,0 +1,26 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Dialog 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Dialog#theming + */ +.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } +.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } +.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } +.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } +.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } +.ui-draggable .ui-dialog-titlebar { cursor: move; } diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.progressbar.css b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.progressbar.css new file mode 100644 index 000000000..6e8718e03 --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.progressbar.css @@ -0,0 +1,16 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Progressbar 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Progressbar#theming + */ +.ui-progressbar { height:2em; text-align: left; } +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } \ No newline at end of file diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.resizable.css b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.resizable.css new file mode 100644 index 000000000..bf037be18 --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.resizable.css @@ -0,0 +1,25 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Resizable 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)] + * + * http://docs.jquery.com/UI/Resizable#theming + */ +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;} \ No newline at end of file diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.selectable.css b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.selectable.css new file mode 100644 index 000000000..011416b6f --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.selectable.css @@ -0,0 +1,15 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Selectable 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Selectable#theming + */ +.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.slider.css b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.slider.css new file mode 100644 index 000000000..3bbfb932d --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.slider.css @@ -0,0 +1,29 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Slider 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Slider#theming + */ +.ui-slider { position: relative; text-align: left; } +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } + +.ui-slider-horizontal { height: .8em; } +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: .8em; height: 100px; } +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; } \ No newline at end of file diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.tabs.css b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.tabs.css new file mode 100644 index 000000000..aa5cd8a54 --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.tabs.css @@ -0,0 +1,23 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI Tabs 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Tabs#theming + */ +.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ +.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } +.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } +.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } +.ui-tabs .ui-tabs-hide { display: none !important; } diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.theme.css b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.theme.css new file mode 100644 index 000000000..0d5b73546 --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Content/themes/base/jquery.ui.theme.css @@ -0,0 +1,257 @@ +/* + * Note: While Microsoft is not the author of this file, Microsoft is + * offering you a license subject to the terms of the Microsoft Software + * License Terms for Microsoft ASP.NET Model View Controller 3. + * Microsoft reserves all other rights. The notices below are provided + * for informational purposes only and are not the license terms under + * which Microsoft distributed this file. + * + * jQuery UI CSS Framework 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * + * http://docs.jquery.com/UI/Theming/API + * + * To view and modify this theme, visit http://jqueryui.com/themeroller/ + */ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; } +.ui-widget .ui-widget { font-size: 1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; } +.ui-widget-content { border: 1px solid #aaaaaa/*{borderColorContent}*/; background: #ffffff/*{bgColorContent}*/ url(images/ui-bg_flat_75_ffffff_40x100.png)/*{bgImgUrlContent}*/ 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; color: #222222/*{fcContent}*/; } +.ui-widget-content a { color: #222222/*{fcContent}*/; } +.ui-widget-header { border: 1px solid #aaaaaa/*{borderColorHeader}*/; background: #cccccc/*{bgColorHeader}*/ url(images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; color: #222222/*{fcHeader}*/; font-weight: bold; } +.ui-widget-header a { color: #222222/*{fcHeader}*/; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; } +.ui-state-hover a, .ui-state-hover a:hover { color: #212121/*{fcHover}*/; text-decoration: none; } +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; } +.ui-widget :active { outline: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; } +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; } +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a/*{fcError}*/; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; } +.ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; } +.ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; } +.ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; } +.ui-corner-top { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; } +.ui-corner-bottom { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; } +.ui-corner-right { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; } +.ui-corner-left { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; } +.ui-corner-all { -moz-border-radius: 4px/*{cornerRadius}*/; -webkit-border-radius: 4px/*{cornerRadius}*/; border-radius: 4px/*{cornerRadius}*/; } + +/* Overlays */ +.ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; } +.ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; } \ No newline at end of file diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Scripts/jquery-ui-1.8.11.js.REMOVED.git-id b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Scripts/jquery-ui-1.8.11.js.REMOVED.git-id new file mode 100644 index 000000000..281a68518 --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Scripts/jquery-ui-1.8.11.js.REMOVED.git-id @@ -0,0 +1 @@ +79285779228262f9c021d1ee5a455c6f7f4c1113 \ No newline at end of file diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Scripts/jquery-ui-1.8.11.min.js.REMOVED.git-id b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Scripts/jquery-ui-1.8.11.min.js.REMOVED.git-id new file mode 100644 index 000000000..ec266dd80 --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/Content/Scripts/jquery-ui-1.8.11.min.js.REMOVED.git-id @@ -0,0 +1 @@ +89ff61bcba0fbfbe359c0d3734942d260b702a4b \ No newline at end of file diff --git a/src/Test/packages/jQuery.UI.Combined.1.8.11/jQuery.UI.Combined.1.8.11.nupkg.REMOVED.git-id b/src/Test/packages/jQuery.UI.Combined.1.8.11/jQuery.UI.Combined.1.8.11.nupkg.REMOVED.git-id new file mode 100644 index 000000000..f168d8cf1 --- /dev/null +++ b/src/Test/packages/jQuery.UI.Combined.1.8.11/jQuery.UI.Combined.1.8.11.nupkg.REMOVED.git-id @@ -0,0 +1 @@ +fec4bd7ea4b03d4eb775a39e20dc1d4da6a928ae \ No newline at end of file diff --git a/src/Test/packages/jQuery.Validation.1.8.0/Content/Scripts/jquery.validate-vsdoc.js b/src/Test/packages/jQuery.Validation.1.8.0/Content/Scripts/jquery.validate-vsdoc.js new file mode 100644 index 000000000..30774ac11 --- /dev/null +++ b/src/Test/packages/jQuery.Validation.1.8.0/Content/Scripts/jquery.validate-vsdoc.js @@ -0,0 +1,1299 @@ +/* +* This file has been commented to support Visual Studio Intellisense. +* You should not use this file at runtime inside the browser--it is only +* intended to be used only for design-time IntelliSense. Please use the +* standard jQuery library for all production use. +* +* Comment version: 1.8 +*/ + +/* +* Note: While Microsoft is not the author of this file, Microsoft is +* offering you a license subject to the terms of the Microsoft Software +* License Terms for Microsoft ASP.NET Model View Controller 3. +* Microsoft reserves all other rights. The notices below are provided +* for informational purposes only and are not the license terms under +* which Microsoft distributed this file. +* +* jQuery validation plugin 1.8.0 +* +* http://bassistance.de/jquery-plugins/jquery-plugin-validation/ +* http://docs.jquery.com/Plugins/Validation +* +* Copyright (c) 2006 - 2011 Jörn Zaefferer +* +*/ + +(function($) { + +$.extend($.fn, { + // http://docs.jquery.com/Plugins/Validation/validate + validate: function( options ) { + ///

    + /// Validates the selected form. This method sets up event handlers for submit, focus, + /// keyup, blur and click to trigger validation of the entire form or individual + /// elements. Each one can be disabled, see the onxxx options (onsubmit, onfocusout, + /// onkeyup, onclick). focusInvalid focuses elements when submitting a invalid form. + /// + /// + /// A set of key/value pairs that configure the validate. All options are optional. + /// + /// + + // if nothing is selected, return nothing; can't chain anyway + if (!this.length) { + options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" ); + return; + } + + // check if a validator for this form was already created + var validator = $.data(this[0], 'validator'); + if ( validator ) { + return validator; + } + + validator = new $.validator( options, this[0] ); + $.data(this[0], 'validator', validator); + + if ( validator.settings.onsubmit ) { + + // allow suppresing validation by adding a cancel class to the submit button + this.find("input, button").filter(".cancel").click(function() { + validator.cancelSubmit = true; + }); + + // when a submitHandler is used, capture the submitting button + if (validator.settings.submitHandler) { + this.find("input, button").filter(":submit").click(function() { + validator.submitButton = this; + }); + } + + // validate the form on submit + this.submit( function( event ) { + if ( validator.settings.debug ) + // prevent form submit to be able to see console output + event.preventDefault(); + + function handle() { + if ( validator.settings.submitHandler ) { + if (validator.submitButton) { + // insert a hidden input as a replacement for the missing submit button + var hidden = $("").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm); + } + validator.settings.submitHandler.call( validator, validator.currentForm ); + if (validator.submitButton) { + // and clean up afterwards; thanks to no-block-scope, hidden can be referenced + hidden.remove(); + } + return false; + } + return true; + } + + // prevent submit for invalid forms or custom submit handlers + if ( validator.cancelSubmit ) { + validator.cancelSubmit = false; + return handle(); + } + if ( validator.form() ) { + if ( validator.pendingRequest ) { + validator.formSubmitted = true; + return false; + } + return handle(); + } else { + validator.focusInvalid(); + return false; + } + }); + } + + return validator; + }, + // http://docs.jquery.com/Plugins/Validation/valid + valid: function() { + /// + /// Checks if the selected form is valid or if all selected elements are valid. + /// validate() needs to be called on the form before checking it using this method. + /// + /// + + if ( $(this[0]).is('form')) { + return this.validate().form(); + } else { + var valid = true; + var validator = $(this[0].form).validate(); + this.each(function() { + valid &= validator.element(this); + }); + return valid; + } + }, + // attributes: space seperated list of attributes to retrieve and remove + removeAttrs: function(attributes) { + /// + /// Remove the specified attributes from the first matched element and return them. + /// + /// + /// A space-seperated list of attribute names to remove. + /// + /// + + var result = {}, + $element = this; + $.each(attributes.split(/\s/), function(index, value) { + result[value] = $element.attr(value); + $element.removeAttr(value); + }); + return result; + }, + // http://docs.jquery.com/Plugins/Validation/rules + rules: function(command, argument) { + /// + /// Return the validations rules for the first selected element. + /// + /// + /// Can be either "add" or "remove". + /// + /// + /// A list of rules to add or remove. + /// + /// + + var element = this[0]; + + if (command) { + var settings = $.data(element.form, 'validator').settings; + var staticRules = settings.rules; + var existingRules = $.validator.staticRules(element); + switch(command) { + case "add": + $.extend(existingRules, $.validator.normalizeRule(argument)); + staticRules[element.name] = existingRules; + if (argument.messages) + settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages ); + break; + case "remove": + if (!argument) { + delete staticRules[element.name]; + return existingRules; + } + var filtered = {}; + $.each(argument.split(/\s/), function(index, method) { + filtered[method] = existingRules[method]; + delete existingRules[method]; + }); + return filtered; + } + } + + var data = $.validator.normalizeRules( + $.extend( + {}, + $.validator.metadataRules(element), + $.validator.classRules(element), + $.validator.attributeRules(element), + $.validator.staticRules(element) + ), element); + + // make sure required is at front + if (data.required) { + var param = data.required; + delete data.required; + data = $.extend({required: param}, data); + } + + return data; + } +}); + +// Custom selectors +$.extend($.expr[":"], { + // http://docs.jquery.com/Plugins/Validation/blank + blank: function(a) {return !$.trim("" + a.value);}, + // http://docs.jquery.com/Plugins/Validation/filled + filled: function(a) {return !!$.trim("" + a.value);}, + // http://docs.jquery.com/Plugins/Validation/unchecked + unchecked: function(a) {return !a.checked;} +}); + +// constructor for validator +$.validator = function( options, form ) { + this.settings = $.extend( true, {}, $.validator.defaults, options ); + this.currentForm = form; + this.init(); +}; + +$.validator.format = function(source, params) { + /// + /// Replaces {n} placeholders with arguments. + /// One or more arguments can be passed, in addition to the string template itself, to insert + /// into the string. + /// + /// + /// The string to format. + /// + /// + /// The first argument to insert, or an array of Strings to insert + /// + /// + + if ( arguments.length == 1 ) + return function() { + var args = $.makeArray(arguments); + args.unshift(source); + return $.validator.format.apply( this, args ); + }; + if ( arguments.length > 2 && params.constructor != Array ) { + params = $.makeArray(arguments).slice(1); + } + if ( params.constructor != Array ) { + params = [ params ]; + } + $.each(params, function(i, n) { + source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n); + }); + return source; +}; + +$.extend($.validator, { + + defaults: { + messages: {}, + groups: {}, + rules: {}, + errorClass: "error", + validClass: "valid", + errorElement: "label", + focusInvalid: true, + errorContainer: $( [] ), + errorLabelContainer: $( [] ), + onsubmit: true, + ignore: [], + ignoreTitle: false, + onfocusin: function(element) { + this.lastActive = element; + + // hide error label and remove error class on focus if enabled + if ( this.settings.focusCleanup && !this.blockFocusCleanup ) { + this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass ); + this.addWrapper(this.errorsFor(element)).hide(); + } + }, + onfocusout: function(element) { + if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) { + this.element(element); + } + }, + onkeyup: function(element) { + if ( element.name in this.submitted || element == this.lastElement ) { + this.element(element); + } + }, + onclick: function(element) { + // click on selects, radiobuttons and checkboxes + if ( element.name in this.submitted ) + this.element(element); + // or option elements, check parent select in that case + else if (element.parentNode.name in this.submitted) + this.element(element.parentNode); + }, + highlight: function( element, errorClass, validClass ) { + $(element).addClass(errorClass).removeClass(validClass); + }, + unhighlight: function( element, errorClass, validClass ) { + $(element).removeClass(errorClass).addClass(validClass); + } + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults + setDefaults: function(settings) { + /// + /// Modify default settings for validation. + /// Accepts everything that Plugins/Validation/validate accepts. + /// + /// + /// Options to set as default. + /// + /// + + $.extend( $.validator.defaults, settings ); + }, + + messages: { + required: "This field is required.", + remote: "Please fix this field.", + email: "Please enter a valid email address.", + url: "Please enter a valid URL.", + date: "Please enter a valid date.", + dateISO: "Please enter a valid date (ISO).", + number: "Please enter a valid number.", + digits: "Please enter only digits.", + creditcard: "Please enter a valid credit card number.", + equalTo: "Please enter the same value again.", + accept: "Please enter a value with a valid extension.", + maxlength: $.validator.format("Please enter no more than {0} characters."), + minlength: $.validator.format("Please enter at least {0} characters."), + rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."), + range: $.validator.format("Please enter a value between {0} and {1}."), + max: $.validator.format("Please enter a value less than or equal to {0}."), + min: $.validator.format("Please enter a value greater than or equal to {0}.") + }, + + autoCreateRanges: false, + + prototype: { + + init: function() { + this.labelContainer = $(this.settings.errorLabelContainer); + this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm); + this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer ); + this.submitted = {}; + this.valueCache = {}; + this.pendingRequest = 0; + this.pending = {}; + this.invalid = {}; + this.reset(); + + var groups = (this.groups = {}); + $.each(this.settings.groups, function(key, value) { + $.each(value.split(/\s/), function(index, name) { + groups[name] = key; + }); + }); + var rules = this.settings.rules; + $.each(rules, function(key, value) { + rules[key] = $.validator.normalizeRule(value); + }); + + function delegate(event) { + var validator = $.data(this[0].form, "validator"), + eventType = "on" + event.type.replace(/^validate/, ""); + validator.settings[eventType] && validator.settings[eventType].call(validator, this[0] ); + } + $(this.currentForm) + .validateDelegate(":text, :password, :file, select, textarea", "focusin focusout keyup", delegate) + .validateDelegate(":radio, :checkbox, select, option", "click", delegate); + + if (this.settings.invalidHandler) + $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler); + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/form + form: function() { + /// + /// Validates the form, returns true if it is valid, false otherwise. + /// This behaves as a normal submit event, but returns the result. + /// + /// + + this.checkForm(); + $.extend(this.submitted, this.errorMap); + this.invalid = $.extend({}, this.errorMap); + if (!this.valid()) + $(this.currentForm).triggerHandler("invalid-form", [this]); + this.showErrors(); + return this.valid(); + }, + + checkForm: function() { + this.prepareForm(); + for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) { + this.check( elements[i] ); + } + return this.valid(); + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/element + element: function( element ) { + /// + /// Validates a single element, returns true if it is valid, false otherwise. + /// This behaves as validation on blur or keyup, but returns the result. + /// + /// + /// An element to validate, must be inside the validated form. + /// + /// + + element = this.clean( element ); + this.lastElement = element; + this.prepareElement( element ); + this.currentElements = $(element); + var result = this.check( element ); + if ( result ) { + delete this.invalid[element.name]; + } else { + this.invalid[element.name] = true; + } + if ( !this.numberOfInvalids() ) { + // Hide error containers on last error + this.toHide = this.toHide.add( this.containers ); + } + this.showErrors(); + return result; + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/showErrors + showErrors: function(errors) { + /// + /// Show the specified messages. + /// Keys have to refer to the names of elements, values are displayed for those elements, using the configured error placement. + /// + /// + /// One or more key/value pairs of input names and messages. + /// + /// + + if(errors) { + // add items to error list and map + $.extend( this.errorMap, errors ); + this.errorList = []; + for ( var name in errors ) { + this.errorList.push({ + message: errors[name], + element: this.findByName(name)[0] + }); + } + // remove items from success list + this.successList = $.grep( this.successList, function(element) { + return !(element.name in errors); + }); + } + this.settings.showErrors + ? this.settings.showErrors.call( this, this.errorMap, this.errorList ) + : this.defaultShowErrors(); + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/resetForm + resetForm: function() { + /// + /// Resets the controlled form. + /// Resets input fields to their original value (requires form plugin), removes classes + /// indicating invalid elements and hides error messages. + /// + /// + + if ( $.fn.resetForm ) + $( this.currentForm ).resetForm(); + this.submitted = {}; + this.prepareForm(); + this.hideErrors(); + this.elements().removeClass( this.settings.errorClass ); + }, + + numberOfInvalids: function() { + /// + /// Returns the number of invalid fields. + /// This depends on the internal validator state. It covers all fields only after + /// validating the complete form (on submit or via $("form").valid()). After validating + /// a single element, only that element is counted. Most useful in combination with the + /// invalidHandler-option. + /// + /// + + return this.objectLength(this.invalid); + }, + + objectLength: function( obj ) { + var count = 0; + for ( var i in obj ) + count++; + return count; + }, + + hideErrors: function() { + this.addWrapper( this.toHide ).hide(); + }, + + valid: function() { + return this.size() == 0; + }, + + size: function() { + return this.errorList.length; + }, + + focusInvalid: function() { + if( this.settings.focusInvalid ) { + try { + $(this.findLastActive() || this.errorList.length && this.errorList[0].element || []) + .filter(":visible") + .focus() + // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find + .trigger("focusin"); + } catch(e) { + // ignore IE throwing errors when focusing hidden elements + } + } + }, + + findLastActive: function() { + var lastActive = this.lastActive; + return lastActive && $.grep(this.errorList, function(n) { + return n.element.name == lastActive.name; + }).length == 1 && lastActive; + }, + + elements: function() { + var validator = this, + rulesCache = {}; + + // select all valid inputs inside the form (no submit or reset buttons) + // workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved + return $([]).add(this.currentForm.elements) + .filter(":input") + .not(":submit, :reset, :image, [disabled]") + .not( this.settings.ignore ) + .filter(function() { + !this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this); + + // select only the first element for each name, and only those with rules specified + if ( this.name in rulesCache || !validator.objectLength($(this).rules()) ) + return false; + + rulesCache[this.name] = true; + return true; + }); + }, + + clean: function( selector ) { + return $( selector )[0]; + }, + + errors: function() { + return $( this.settings.errorElement + "." + this.settings.errorClass, this.errorContext ); + }, + + reset: function() { + this.successList = []; + this.errorList = []; + this.errorMap = {}; + this.toShow = $([]); + this.toHide = $([]); + this.currentElements = $([]); + }, + + prepareForm: function() { + this.reset(); + this.toHide = this.errors().add( this.containers ); + }, + + prepareElement: function( element ) { + this.reset(); + this.toHide = this.errorsFor(element); + }, + + check: function( element ) { + element = this.clean( element ); + + // if radio/checkbox, validate first element in group instead + if (this.checkable(element)) { + element = this.findByName(element.name).not(this.settings.ignore)[0]; + } + + var rules = $(element).rules(); + var dependencyMismatch = false; + for (var method in rules) { + var rule = { method: method, parameters: rules[method] }; + try { + var result = $.validator.methods[method].call( this, element.value.replace(/\r/g, ""), element, rule.parameters ); + + // if a method indicates that the field is optional and therefore valid, + // don't mark it as valid when there are no other rules + if ( result == "dependency-mismatch" ) { + dependencyMismatch = true; + continue; + } + dependencyMismatch = false; + + if ( result == "pending" ) { + this.toHide = this.toHide.not( this.errorsFor(element) ); + return; + } + + if( !result ) { + this.formatAndAdd( element, rule ); + return false; + } + } catch(e) { + this.settings.debug && window.console && console.log("exception occured when checking element " + element.id + + ", check the '" + rule.method + "' method", e); + throw e; + } + } + if (dependencyMismatch) + return; + if ( this.objectLength(rules) ) + this.successList.push(element); + return true; + }, + + // return the custom message for the given element and validation method + // specified in the element's "messages" metadata + customMetaMessage: function(element, method) { + if (!$.metadata) + return; + + var meta = this.settings.meta + ? $(element).metadata()[this.settings.meta] + : $(element).metadata(); + + return meta && meta.messages && meta.messages[method]; + }, + + // return the custom message for the given element name and validation method + customMessage: function( name, method ) { + var m = this.settings.messages[name]; + return m && (m.constructor == String + ? m + : m[method]); + }, + + // return the first defined argument, allowing empty strings + findDefined: function() { + for(var i = 0; i < arguments.length; i++) { + if (arguments[i] !== undefined) + return arguments[i]; + } + return undefined; + }, + + defaultMessage: function( element, method) { + return this.findDefined( + this.customMessage( element.name, method ), + this.customMetaMessage( element, method ), + // title is never undefined, so handle empty string as undefined + !this.settings.ignoreTitle && element.title || undefined, + $.validator.messages[method], + "Warning: No message defined for " + element.name + "" + ); + }, + + formatAndAdd: function( element, rule ) { + var message = this.defaultMessage( element, rule.method ), + theregex = /\$?\{(\d+)\}/g; + if ( typeof message == "function" ) { + message = message.call(this, rule.parameters, element); + } else if (theregex.test(message)) { + message = jQuery.format(message.replace(theregex, '{$1}'), rule.parameters); + } + this.errorList.push({ + message: message, + element: element + }); + + this.errorMap[element.name] = message; + this.submitted[element.name] = message; + }, + + addWrapper: function(toToggle) { + if ( this.settings.wrapper ) + toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) ); + return toToggle; + }, + + defaultShowErrors: function() { + for ( var i = 0; this.errorList[i]; i++ ) { + var error = this.errorList[i]; + this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass ); + this.showLabel( error.element, error.message ); + } + if( this.errorList.length ) { + this.toShow = this.toShow.add( this.containers ); + } + if (this.settings.success) { + for ( var i = 0; this.successList[i]; i++ ) { + this.showLabel( this.successList[i] ); + } + } + if (this.settings.unhighlight) { + for ( var i = 0, elements = this.validElements(); elements[i]; i++ ) { + this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass ); + } + } + this.toHide = this.toHide.not( this.toShow ); + this.hideErrors(); + this.addWrapper( this.toShow ).show(); + }, + + validElements: function() { + return this.currentElements.not(this.invalidElements()); + }, + + invalidElements: function() { + return $(this.errorList).map(function() { + return this.element; + }); + }, + + showLabel: function(element, message) { + var label = this.errorsFor( element ); + if ( label.length ) { + // refresh error/success class + label.removeClass().addClass( this.settings.errorClass ); + + // check if we have a generated label, replace the message then + label.attr("generated") && label.html(message); + } else { + // create label + label = $("<" + this.settings.errorElement + "/>") + .attr({"for": this.idOrName(element), generated: true}) + .addClass(this.settings.errorClass) + .html(message || ""); + if ( this.settings.wrapper ) { + // make sure the element is visible, even in IE + // actually showing the wrapped element is handled elsewhere + label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent(); + } + if ( !this.labelContainer.append(label).length ) + this.settings.errorPlacement + ? this.settings.errorPlacement(label, $(element) ) + : label.insertAfter(element); + } + if ( !message && this.settings.success ) { + label.text(""); + typeof this.settings.success == "string" + ? label.addClass( this.settings.success ) + : this.settings.success( label ); + } + this.toShow = this.toShow.add(label); + }, + + errorsFor: function(element) { + var name = this.idOrName(element); + return this.errors().filter(function() { + return $(this).attr('for') == name; + }); + }, + + idOrName: function(element) { + return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name); + }, + + checkable: function( element ) { + return /radio|checkbox/i.test(element.type); + }, + + findByName: function( name ) { + // select by name and filter by form for performance over form.find("[name=...]") + var form = this.currentForm; + return $(document.getElementsByName(name)).map(function(index, element) { + return element.form == form && element.name == name && element || null; + }); + }, + + getLength: function(value, element) { + switch( element.nodeName.toLowerCase() ) { + case 'select': + return $("option:selected", element).length; + case 'input': + if( this.checkable( element) ) + return this.findByName(element.name).filter(':checked').length; + } + return value.length; + }, + + depend: function(param, element) { + return this.dependTypes[typeof param] + ? this.dependTypes[typeof param](param, element) + : true; + }, + + dependTypes: { + "boolean": function(param, element) { + return param; + }, + "string": function(param, element) { + return !!$(param, element.form).length; + }, + "function": function(param, element) { + return param(element); + } + }, + + optional: function(element) { + return !$.validator.methods.required.call(this, $.trim(element.value), element) && "dependency-mismatch"; + }, + + startRequest: function(element) { + if (!this.pending[element.name]) { + this.pendingRequest++; + this.pending[element.name] = true; + } + }, + + stopRequest: function(element, valid) { + this.pendingRequest--; + // sometimes synchronization fails, make sure pendingRequest is never < 0 + if (this.pendingRequest < 0) + this.pendingRequest = 0; + delete this.pending[element.name]; + if ( valid && this.pendingRequest == 0 && this.formSubmitted && this.form() ) { + $(this.currentForm).submit(); + this.formSubmitted = false; + } else if (!valid && this.pendingRequest == 0 && this.formSubmitted) { + $(this.currentForm).triggerHandler("invalid-form", [this]); + this.formSubmitted = false; + } + }, + + previousValue: function(element) { + return $.data(element, "previousValue") || $.data(element, "previousValue", { + old: null, + valid: true, + message: this.defaultMessage( element, "remote" ) + }); + } + + }, + + classRuleSettings: { + required: {required: true}, + email: {email: true}, + url: {url: true}, + date: {date: true}, + dateISO: {dateISO: true}, + dateDE: {dateDE: true}, + number: {number: true}, + numberDE: {numberDE: true}, + digits: {digits: true}, + creditcard: {creditcard: true} + }, + + addClassRules: function(className, rules) { + /// + /// Add a compound class method - useful to refactor common combinations of rules into a single + /// class. + /// + /// + /// The name of the class rule to add + /// + /// + /// The compound rules + /// + /// + + className.constructor == String ? + this.classRuleSettings[className] = rules : + $.extend(this.classRuleSettings, className); + }, + + classRules: function(element) { + var rules = {}; + var classes = $(element).attr('class'); + classes && $.each(classes.split(' '), function() { + if (this in $.validator.classRuleSettings) { + $.extend(rules, $.validator.classRuleSettings[this]); + } + }); + return rules; + }, + + attributeRules: function(element) { + var rules = {}; + var $element = $(element); + + for (var method in $.validator.methods) { + var value = $element.attr(method); + if (value) { + rules[method] = value; + } + } + + // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs + if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) { + delete rules.maxlength; + } + + return rules; + }, + + metadataRules: function(element) { + if (!$.metadata) return {}; + + var meta = $.data(element.form, 'validator').settings.meta; + return meta ? + $(element).metadata()[meta] : + $(element).metadata(); + }, + + staticRules: function(element) { + var rules = {}; + var validator = $.data(element.form, 'validator'); + if (validator.settings.rules) { + rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {}; + } + return rules; + }, + + normalizeRules: function(rules, element) { + // handle dependency check + $.each(rules, function(prop, val) { + // ignore rule when param is explicitly false, eg. required:false + if (val === false) { + delete rules[prop]; + return; + } + if (val.param || val.depends) { + var keepRule = true; + switch (typeof val.depends) { + case "string": + keepRule = !!$(val.depends, element.form).length; + break; + case "function": + keepRule = val.depends.call(element, element); + break; + } + if (keepRule) { + rules[prop] = val.param !== undefined ? val.param : true; + } else { + delete rules[prop]; + } + } + }); + + // evaluate parameters + $.each(rules, function(rule, parameter) { + rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter; + }); + + // clean number parameters + $.each(['minlength', 'maxlength', 'min', 'max'], function() { + if (rules[this]) { + rules[this] = Number(rules[this]); + } + }); + $.each(['rangelength', 'range'], function() { + if (rules[this]) { + rules[this] = [Number(rules[this][0]), Number(rules[this][1])]; + } + }); + + if ($.validator.autoCreateRanges) { + // auto-create ranges + if (rules.min && rules.max) { + rules.range = [rules.min, rules.max]; + delete rules.min; + delete rules.max; + } + if (rules.minlength && rules.maxlength) { + rules.rangelength = [rules.minlength, rules.maxlength]; + delete rules.minlength; + delete rules.maxlength; + } + } + + // To support custom messages in metadata ignore rule methods titled "messages" + if (rules.messages) { + delete rules.messages; + } + + return rules; + }, + + // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true} + normalizeRule: function(data) { + if( typeof data == "string" ) { + var transformed = {}; + $.each(data.split(/\s/), function() { + transformed[this] = true; + }); + data = transformed; + } + return data; + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/addMethod + addMethod: function(name, method, message) { + /// + /// Add a custom validation method. It must consist of a name (must be a legal javascript + /// identifier), a javascript based function and a default string message. + /// + /// + /// The name of the method, used to identify and referencing it, must be a valid javascript + /// identifier + /// + /// + /// The actual method implementation, returning true if an element is valid + /// + /// + /// (Optional) The default message to display for this method. Can be a function created by + /// jQuery.validator.format(value). When undefined, an already existing message is used + /// (handy for localization), otherwise the field-specific messages have to be defined. + /// + /// + + $.validator.methods[name] = method; + $.validator.messages[name] = message != undefined ? message : $.validator.messages[name]; + if (method.length < 3) { + $.validator.addClassRules(name, $.validator.normalizeRule(name)); + } + }, + + methods: { + + // http://docs.jquery.com/Plugins/Validation/Methods/required + required: function(value, element, param) { + // check if dependency is met + if ( !this.depend(param, element) ) + return "dependency-mismatch"; + switch( element.nodeName.toLowerCase() ) { + case 'select': + // could be an array for select-multiple or a string, both are fine this way + var val = $(element).val(); + return val && val.length > 0; + case 'input': + if ( this.checkable(element) ) + return this.getLength(value, element) > 0; + default: + return $.trim(value).length > 0; + } + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/remote + remote: function(value, element, param) { + if ( this.optional(element) ) + return "dependency-mismatch"; + + var previous = this.previousValue(element); + if (!this.settings.messages[element.name] ) + this.settings.messages[element.name] = {}; + previous.originalMessage = this.settings.messages[element.name].remote; + this.settings.messages[element.name].remote = previous.message; + + param = typeof param == "string" && {url:param} || param; + + if ( this.pending[element.name] ) { + return "pending"; + } + if ( previous.old === value ) { + return previous.valid; + } + + previous.old = value; + var validator = this; + this.startRequest(element); + var data = {}; + data[element.name] = value; + $.ajax($.extend(true, { + url: param, + mode: "abort", + port: "validate" + element.name, + dataType: "json", + data: data, + success: function(response) { + validator.settings.messages[element.name].remote = previous.originalMessage; + var valid = response === true; + if ( valid ) { + var submitted = validator.formSubmitted; + validator.prepareElement(element); + validator.formSubmitted = submitted; + validator.successList.push(element); + validator.showErrors(); + } else { + var errors = {}; + var message = response || validator.defaultMessage(element, "remote"); + errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message; + validator.showErrors(errors); + } + previous.valid = valid; + validator.stopRequest(element, valid); + } + }, param)); + return "pending"; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/minlength + minlength: function(value, element, param) { + return this.optional(element) || this.getLength($.trim(value), element) >= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/maxlength + maxlength: function(value, element, param) { + return this.optional(element) || this.getLength($.trim(value), element) <= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/rangelength + rangelength: function(value, element, param) { + var length = this.getLength($.trim(value), element); + return this.optional(element) || ( length >= param[0] && length <= param[1] ); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/min + min: function( value, element, param ) { + return this.optional(element) || value >= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/max + max: function( value, element, param ) { + return this.optional(element) || value <= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/range + range: function( value, element, param ) { + return this.optional(element) || ( value >= param[0] && value <= param[1] ); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/email + email: function(value, element) { + // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/ + return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([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])))\.?$/i.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/url + url: function(value, element) { + // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/ + 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); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/date + date: function(value, element) { + return this.optional(element) || !/Invalid|NaN/.test(new Date(value)); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/dateISO + dateISO: function(value, element) { + return this.optional(element) || /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/number + number: function(value, element) { + return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/digits + digits: function(value, element) { + return this.optional(element) || /^\d+$/.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/creditcard + // based on http://en.wikipedia.org/wiki/Luhn + creditcard: function(value, element) { + if ( this.optional(element) ) + return "dependency-mismatch"; + // accept only digits and dashes + if (/[^0-9-]+/.test(value)) + return false; + var nCheck = 0, + nDigit = 0, + bEven = false; + + value = value.replace(/\D/g, ""); + + for (var n = value.length - 1; n >= 0; n--) { + var cDigit = value.charAt(n); + var nDigit = parseInt(cDigit, 10); + if (bEven) { + if ((nDigit *= 2) > 9) + nDigit -= 9; + } + nCheck += nDigit; + bEven = !bEven; + } + + return (nCheck % 10) == 0; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/accept + accept: function(value, element, param) { + param = typeof param == "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif"; + return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i")); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/equalTo + equalTo: function(value, element, param) { + // bind to the blur event of the target in order to revalidate whenever the target field is updated + // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead + var target = $(param).unbind(".validate-equalTo").bind("blur.validate-equalTo", function() { + $(element).valid(); + }); + return value == target.val(); + } + + } + +}); + +// deprecated, use $.validator.format instead +$.format = $.validator.format; + +})(jQuery); + +// ajax mode: abort +// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]}); +// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() +;(function($) { + var pendingRequests = {}; + // Use a prefilter if available (1.5+) + if ( $.ajaxPrefilter ) { + $.ajaxPrefilter(function(settings, _, xhr) { + var port = settings.port; + if (settings.mode == "abort") { + if ( pendingRequests[port] ) { + pendingRequests[port].abort(); + } pendingRequests[port] = xhr; + } + }); + } else { + // Proxy ajax + var ajax = $.ajax; + $.ajax = function(settings) { + var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode, + port = ( "port" in settings ? settings : $.ajaxSettings ).port; + if (mode == "abort") { + if ( pendingRequests[port] ) { + pendingRequests[port].abort(); + } + + return (pendingRequests[port] = ajax.apply(this, arguments)); + } + return ajax.apply(this, arguments); + }; + } +})(jQuery); + +// provides cross-browser focusin and focusout events +// IE has native support, in other browsers, use event caputuring (neither bubbles) + +// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation +// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target +;(function($) { + // only implement if not provided by jQuery core (since 1.4) + // TODO verify if jQuery 1.4's implementation is compatible with older jQuery special-event APIs + if (!jQuery.event.special.focusin && !jQuery.event.special.focusout && document.addEventListener) { + $.each({ + focus: 'focusin', + blur: 'focusout' + }, function( original, fix ){ + $.event.special[fix] = { + setup:function() { + this.addEventListener( original, handler, true ); + }, + teardown:function() { + this.removeEventListener( original, handler, true ); + }, + handler: function(e) { + arguments[0] = $.event.fix(e); + arguments[0].type = fix; + return $.event.handle.apply(this, arguments); + } + }; + function handler(e) { + e = $.event.fix(e); + e.type = fix; + return $.event.handle.call(this, e); + } + }); + }; + $.extend($.fn, { + validateDelegate: function(delegate, type, handler) { + return this.bind(type, function(event) { + var target = $(event.target); + if (target.is(delegate)) { + return handler.apply(target, arguments); + } + }); + } + }); +})(jQuery); diff --git a/src/Test/packages/jQuery.Validation.1.8.0/Content/Scripts/jquery.validate.js b/src/Test/packages/jQuery.Validation.1.8.0/Content/Scripts/jquery.validate.js new file mode 100644 index 000000000..4ba1ad970 --- /dev/null +++ b/src/Test/packages/jQuery.Validation.1.8.0/Content/Scripts/jquery.validate.js @@ -0,0 +1,1162 @@ +/** +* Note: While Microsoft is not the author of this file, Microsoft is +* offering you a license subject to the terms of the Microsoft Software +* License Terms for Microsoft ASP.NET Model View Controller 3. +* Microsoft reserves all other rights. The notices below are provided +* for informational purposes only and are not the license terms under +* which Microsoft distributed this file. +* +* jQuery Validation Plugin 1.8.0 +* +* http://bassistance.de/jquery-plugins/jquery-plugin-validation/ +* http://docs.jquery.com/Plugins/Validation +* +* Copyright (c) 2006 - 2011 Jörn Zaefferer +*/ + +(function($) { + +$.extend($.fn, { + // http://docs.jquery.com/Plugins/Validation/validate + validate: function( options ) { + + // if nothing is selected, return nothing; can't chain anyway + if (!this.length) { + options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" ); + return; + } + + // check if a validator for this form was already created + var validator = $.data(this[0], 'validator'); + if ( validator ) { + return validator; + } + + validator = new $.validator( options, this[0] ); + $.data(this[0], 'validator', validator); + + if ( validator.settings.onsubmit ) { + + // allow suppresing validation by adding a cancel class to the submit button + this.find("input, button").filter(".cancel").click(function() { + validator.cancelSubmit = true; + }); + + // when a submitHandler is used, capture the submitting button + if (validator.settings.submitHandler) { + this.find("input, button").filter(":submit").click(function() { + validator.submitButton = this; + }); + } + + // validate the form on submit + this.submit( function( event ) { + if ( validator.settings.debug ) + // prevent form submit to be able to see console output + event.preventDefault(); + + function handle() { + if ( validator.settings.submitHandler ) { + if (validator.submitButton) { + // insert a hidden input as a replacement for the missing submit button + var hidden = $("").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm); + } + validator.settings.submitHandler.call( validator, validator.currentForm ); + if (validator.submitButton) { + // and clean up afterwards; thanks to no-block-scope, hidden can be referenced + hidden.remove(); + } + return false; + } + return true; + } + + // prevent submit for invalid forms or custom submit handlers + if ( validator.cancelSubmit ) { + validator.cancelSubmit = false; + return handle(); + } + if ( validator.form() ) { + if ( validator.pendingRequest ) { + validator.formSubmitted = true; + return false; + } + return handle(); + } else { + validator.focusInvalid(); + return false; + } + }); + } + + return validator; + }, + // http://docs.jquery.com/Plugins/Validation/valid + valid: function() { + if ( $(this[0]).is('form')) { + return this.validate().form(); + } else { + var valid = true; + var validator = $(this[0].form).validate(); + this.each(function() { + valid &= validator.element(this); + }); + return valid; + } + }, + // attributes: space seperated list of attributes to retrieve and remove + removeAttrs: function(attributes) { + var result = {}, + $element = this; + $.each(attributes.split(/\s/), function(index, value) { + result[value] = $element.attr(value); + $element.removeAttr(value); + }); + return result; + }, + // http://docs.jquery.com/Plugins/Validation/rules + rules: function(command, argument) { + var element = this[0]; + + if (command) { + var settings = $.data(element.form, 'validator').settings; + var staticRules = settings.rules; + var existingRules = $.validator.staticRules(element); + switch(command) { + case "add": + $.extend(existingRules, $.validator.normalizeRule(argument)); + staticRules[element.name] = existingRules; + if (argument.messages) + settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages ); + break; + case "remove": + if (!argument) { + delete staticRules[element.name]; + return existingRules; + } + var filtered = {}; + $.each(argument.split(/\s/), function(index, method) { + filtered[method] = existingRules[method]; + delete existingRules[method]; + }); + return filtered; + } + } + + var data = $.validator.normalizeRules( + $.extend( + {}, + $.validator.metadataRules(element), + $.validator.classRules(element), + $.validator.attributeRules(element), + $.validator.staticRules(element) + ), element); + + // make sure required is at front + if (data.required) { + var param = data.required; + delete data.required; + data = $.extend({required: param}, data); + } + + return data; + } +}); + +// Custom selectors +$.extend($.expr[":"], { + // http://docs.jquery.com/Plugins/Validation/blank + blank: function(a) {return !$.trim("" + a.value);}, + // http://docs.jquery.com/Plugins/Validation/filled + filled: function(a) {return !!$.trim("" + a.value);}, + // http://docs.jquery.com/Plugins/Validation/unchecked + unchecked: function(a) {return !a.checked;} +}); + +// constructor for validator +$.validator = function( options, form ) { + this.settings = $.extend( true, {}, $.validator.defaults, options ); + this.currentForm = form; + this.init(); +}; + +$.validator.format = function(source, params) { + if ( arguments.length == 1 ) + return function() { + var args = $.makeArray(arguments); + args.unshift(source); + return $.validator.format.apply( this, args ); + }; + if ( arguments.length > 2 && params.constructor != Array ) { + params = $.makeArray(arguments).slice(1); + } + if ( params.constructor != Array ) { + params = [ params ]; + } + $.each(params, function(i, n) { + source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n); + }); + return source; +}; + +$.extend($.validator, { + + defaults: { + messages: {}, + groups: {}, + rules: {}, + errorClass: "error", + validClass: "valid", + errorElement: "label", + focusInvalid: true, + errorContainer: $( [] ), + errorLabelContainer: $( [] ), + onsubmit: true, + ignore: [], + ignoreTitle: false, + onfocusin: function(element) { + this.lastActive = element; + + // hide error label and remove error class on focus if enabled + if ( this.settings.focusCleanup && !this.blockFocusCleanup ) { + this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass ); + this.addWrapper(this.errorsFor(element)).hide(); + } + }, + onfocusout: function(element) { + if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) { + this.element(element); + } + }, + onkeyup: function(element) { + if ( element.name in this.submitted || element == this.lastElement ) { + this.element(element); + } + }, + onclick: function(element) { + // click on selects, radiobuttons and checkboxes + if ( element.name in this.submitted ) + this.element(element); + // or option elements, check parent select in that case + else if (element.parentNode.name in this.submitted) + this.element(element.parentNode); + }, + highlight: function( element, errorClass, validClass ) { + $(element).addClass(errorClass).removeClass(validClass); + }, + unhighlight: function( element, errorClass, validClass ) { + $(element).removeClass(errorClass).addClass(validClass); + } + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults + setDefaults: function(settings) { + $.extend( $.validator.defaults, settings ); + }, + + messages: { + required: "This field is required.", + remote: "Please fix this field.", + email: "Please enter a valid email address.", + url: "Please enter a valid URL.", + date: "Please enter a valid date.", + dateISO: "Please enter a valid date (ISO).", + number: "Please enter a valid number.", + digits: "Please enter only digits.", + creditcard: "Please enter a valid credit card number.", + equalTo: "Please enter the same value again.", + accept: "Please enter a value with a valid extension.", + maxlength: $.validator.format("Please enter no more than {0} characters."), + minlength: $.validator.format("Please enter at least {0} characters."), + rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."), + range: $.validator.format("Please enter a value between {0} and {1}."), + max: $.validator.format("Please enter a value less than or equal to {0}."), + min: $.validator.format("Please enter a value greater than or equal to {0}.") + }, + + autoCreateRanges: false, + + prototype: { + + init: function() { + this.labelContainer = $(this.settings.errorLabelContainer); + this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm); + this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer ); + this.submitted = {}; + this.valueCache = {}; + this.pendingRequest = 0; + this.pending = {}; + this.invalid = {}; + this.reset(); + + var groups = (this.groups = {}); + $.each(this.settings.groups, function(key, value) { + $.each(value.split(/\s/), function(index, name) { + groups[name] = key; + }); + }); + var rules = this.settings.rules; + $.each(rules, function(key, value) { + rules[key] = $.validator.normalizeRule(value); + }); + + function delegate(event) { + var validator = $.data(this[0].form, "validator"), + eventType = "on" + event.type.replace(/^validate/, ""); + validator.settings[eventType] && validator.settings[eventType].call(validator, this[0] ); + } + $(this.currentForm) + .validateDelegate(":text, :password, :file, select, textarea", "focusin focusout keyup", delegate) + .validateDelegate(":radio, :checkbox, select, option", "click", delegate); + + if (this.settings.invalidHandler) + $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler); + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/form + form: function() { + this.checkForm(); + $.extend(this.submitted, this.errorMap); + this.invalid = $.extend({}, this.errorMap); + if (!this.valid()) + $(this.currentForm).triggerHandler("invalid-form", [this]); + this.showErrors(); + return this.valid(); + }, + + checkForm: function() { + this.prepareForm(); + for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) { + this.check( elements[i] ); + } + return this.valid(); + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/element + element: function( element ) { + element = this.clean( element ); + this.lastElement = element; + this.prepareElement( element ); + this.currentElements = $(element); + var result = this.check( element ); + if ( result ) { + delete this.invalid[element.name]; + } else { + this.invalid[element.name] = true; + } + if ( !this.numberOfInvalids() ) { + // Hide error containers on last error + this.toHide = this.toHide.add( this.containers ); + } + this.showErrors(); + return result; + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/showErrors + showErrors: function(errors) { + if(errors) { + // add items to error list and map + $.extend( this.errorMap, errors ); + this.errorList = []; + for ( var name in errors ) { + this.errorList.push({ + message: errors[name], + element: this.findByName(name)[0] + }); + } + // remove items from success list + this.successList = $.grep( this.successList, function(element) { + return !(element.name in errors); + }); + } + this.settings.showErrors + ? this.settings.showErrors.call( this, this.errorMap, this.errorList ) + : this.defaultShowErrors(); + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/resetForm + resetForm: function() { + if ( $.fn.resetForm ) + $( this.currentForm ).resetForm(); + this.submitted = {}; + this.prepareForm(); + this.hideErrors(); + this.elements().removeClass( this.settings.errorClass ); + }, + + numberOfInvalids: function() { + return this.objectLength(this.invalid); + }, + + objectLength: function( obj ) { + var count = 0; + for ( var i in obj ) + count++; + return count; + }, + + hideErrors: function() { + this.addWrapper( this.toHide ).hide(); + }, + + valid: function() { + return this.size() == 0; + }, + + size: function() { + return this.errorList.length; + }, + + focusInvalid: function() { + if( this.settings.focusInvalid ) { + try { + $(this.findLastActive() || this.errorList.length && this.errorList[0].element || []) + .filter(":visible") + .focus() + // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find + .trigger("focusin"); + } catch(e) { + // ignore IE throwing errors when focusing hidden elements + } + } + }, + + findLastActive: function() { + var lastActive = this.lastActive; + return lastActive && $.grep(this.errorList, function(n) { + return n.element.name == lastActive.name; + }).length == 1 && lastActive; + }, + + elements: function() { + var validator = this, + rulesCache = {}; + + // select all valid inputs inside the form (no submit or reset buttons) + // workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved + return $([]).add(this.currentForm.elements) + .filter(":input") + .not(":submit, :reset, :image, [disabled]") + .not( this.settings.ignore ) + .filter(function() { + !this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this); + + // select only the first element for each name, and only those with rules specified + if ( this.name in rulesCache || !validator.objectLength($(this).rules()) ) + return false; + + rulesCache[this.name] = true; + return true; + }); + }, + + clean: function( selector ) { + return $( selector )[0]; + }, + + errors: function() { + return $( this.settings.errorElement + "." + this.settings.errorClass, this.errorContext ); + }, + + reset: function() { + this.successList = []; + this.errorList = []; + this.errorMap = {}; + this.toShow = $([]); + this.toHide = $([]); + this.currentElements = $([]); + }, + + prepareForm: function() { + this.reset(); + this.toHide = this.errors().add( this.containers ); + }, + + prepareElement: function( element ) { + this.reset(); + this.toHide = this.errorsFor(element); + }, + + check: function( element ) { + element = this.clean( element ); + + // if radio/checkbox, validate first element in group instead + if (this.checkable(element)) { + element = this.findByName( element.name ).not(this.settings.ignore)[0]; + } + + var rules = $(element).rules(); + var dependencyMismatch = false; + for (var method in rules ) { + var rule = { method: method, parameters: rules[method] }; + try { + var result = $.validator.methods[method].call( this, element.value.replace(/\r/g, ""), element, rule.parameters ); + + // if a method indicates that the field is optional and therefore valid, + // don't mark it as valid when there are no other rules + if ( result == "dependency-mismatch" ) { + dependencyMismatch = true; + continue; + } + dependencyMismatch = false; + + if ( result == "pending" ) { + this.toHide = this.toHide.not( this.errorsFor(element) ); + return; + } + + if( !result ) { + this.formatAndAdd( element, rule ); + return false; + } + } catch(e) { + this.settings.debug && window.console && console.log("exception occured when checking element " + element.id + + ", check the '" + rule.method + "' method", e); + throw e; + } + } + if (dependencyMismatch) + return; + if ( this.objectLength(rules) ) + this.successList.push(element); + return true; + }, + + // return the custom message for the given element and validation method + // specified in the element's "messages" metadata + customMetaMessage: function(element, method) { + if (!$.metadata) + return; + + var meta = this.settings.meta + ? $(element).metadata()[this.settings.meta] + : $(element).metadata(); + + return meta && meta.messages && meta.messages[method]; + }, + + // return the custom message for the given element name and validation method + customMessage: function( name, method ) { + var m = this.settings.messages[name]; + return m && (m.constructor == String + ? m + : m[method]); + }, + + // return the first defined argument, allowing empty strings + findDefined: function() { + for(var i = 0; i < arguments.length; i++) { + if (arguments[i] !== undefined) + return arguments[i]; + } + return undefined; + }, + + defaultMessage: function( element, method) { + return this.findDefined( + this.customMessage( element.name, method ), + this.customMetaMessage( element, method ), + // title is never undefined, so handle empty string as undefined + !this.settings.ignoreTitle && element.title || undefined, + $.validator.messages[method], + "Warning: No message defined for " + element.name + "" + ); + }, + + formatAndAdd: function( element, rule ) { + var message = this.defaultMessage( element, rule.method ), + theregex = /\$?\{(\d+)\}/g; + if ( typeof message == "function" ) { + message = message.call(this, rule.parameters, element); + } else if (theregex.test(message)) { + message = jQuery.format(message.replace(theregex, '{$1}'), rule.parameters); + } + this.errorList.push({ + message: message, + element: element + }); + + this.errorMap[element.name] = message; + this.submitted[element.name] = message; + }, + + addWrapper: function(toToggle) { + if ( this.settings.wrapper ) + toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) ); + return toToggle; + }, + + defaultShowErrors: function() { + for ( var i = 0; this.errorList[i]; i++ ) { + var error = this.errorList[i]; + this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass ); + this.showLabel( error.element, error.message ); + } + if( this.errorList.length ) { + this.toShow = this.toShow.add( this.containers ); + } + if (this.settings.success) { + for ( var i = 0; this.successList[i]; i++ ) { + this.showLabel( this.successList[i] ); + } + } + if (this.settings.unhighlight) { + for ( var i = 0, elements = this.validElements(); elements[i]; i++ ) { + this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass ); + } + } + this.toHide = this.toHide.not( this.toShow ); + this.hideErrors(); + this.addWrapper( this.toShow ).show(); + }, + + validElements: function() { + return this.currentElements.not(this.invalidElements()); + }, + + invalidElements: function() { + return $(this.errorList).map(function() { + return this.element; + }); + }, + + showLabel: function(element, message) { + var label = this.errorsFor( element ); + if ( label.length ) { + // refresh error/success class + label.removeClass().addClass( this.settings.errorClass ); + + // check if we have a generated label, replace the message then + label.attr("generated") && label.html(message); + } else { + // create label + label = $("<" + this.settings.errorElement + "/>") + .attr({"for": this.idOrName(element), generated: true}) + .addClass(this.settings.errorClass) + .html(message || ""); + if ( this.settings.wrapper ) { + // make sure the element is visible, even in IE + // actually showing the wrapped element is handled elsewhere + label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent(); + } + if ( !this.labelContainer.append(label).length ) + this.settings.errorPlacement + ? this.settings.errorPlacement(label, $(element) ) + : label.insertAfter(element); + } + if ( !message && this.settings.success ) { + label.text(""); + typeof this.settings.success == "string" + ? label.addClass( this.settings.success ) + : this.settings.success( label ); + } + this.toShow = this.toShow.add(label); + }, + + errorsFor: function(element) { + var name = this.idOrName(element); + return this.errors().filter(function() { + return $(this).attr('for') == name; + }); + }, + + idOrName: function(element) { + return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name); + }, + + checkable: function( element ) { + return /radio|checkbox/i.test(element.type); + }, + + findByName: function( name ) { + // select by name and filter by form for performance over form.find("[name=...]") + var form = this.currentForm; + return $(document.getElementsByName(name)).map(function(index, element) { + return element.form == form && element.name == name && element || null; + }); + }, + + getLength: function(value, element) { + switch( element.nodeName.toLowerCase() ) { + case 'select': + return $("option:selected", element).length; + case 'input': + if( this.checkable( element) ) + return this.findByName(element.name).filter(':checked').length; + } + return value.length; + }, + + depend: function(param, element) { + return this.dependTypes[typeof param] + ? this.dependTypes[typeof param](param, element) + : true; + }, + + dependTypes: { + "boolean": function(param, element) { + return param; + }, + "string": function(param, element) { + return !!$(param, element.form).length; + }, + "function": function(param, element) { + return param(element); + } + }, + + optional: function(element) { + return !$.validator.methods.required.call(this, $.trim(element.value), element) && "dependency-mismatch"; + }, + + startRequest: function(element) { + if (!this.pending[element.name]) { + this.pendingRequest++; + this.pending[element.name] = true; + } + }, + + stopRequest: function(element, valid) { + this.pendingRequest--; + // sometimes synchronization fails, make sure pendingRequest is never < 0 + if (this.pendingRequest < 0) + this.pendingRequest = 0; + delete this.pending[element.name]; + if ( valid && this.pendingRequest == 0 && this.formSubmitted && this.form() ) { + $(this.currentForm).submit(); + this.formSubmitted = false; + } else if (!valid && this.pendingRequest == 0 && this.formSubmitted) { + $(this.currentForm).triggerHandler("invalid-form", [this]); + this.formSubmitted = false; + } + }, + + previousValue: function(element) { + return $.data(element, "previousValue") || $.data(element, "previousValue", { + old: null, + valid: true, + message: this.defaultMessage( element, "remote" ) + }); + } + + }, + + classRuleSettings: { + required: {required: true}, + email: {email: true}, + url: {url: true}, + date: {date: true}, + dateISO: {dateISO: true}, + dateDE: {dateDE: true}, + number: {number: true}, + numberDE: {numberDE: true}, + digits: {digits: true}, + creditcard: {creditcard: true} + }, + + addClassRules: function(className, rules) { + className.constructor == String ? + this.classRuleSettings[className] = rules : + $.extend(this.classRuleSettings, className); + }, + + classRules: function(element) { + var rules = {}; + var classes = $(element).attr('class'); + classes && $.each(classes.split(' '), function() { + if (this in $.validator.classRuleSettings) { + $.extend(rules, $.validator.classRuleSettings[this]); + } + }); + return rules; + }, + + attributeRules: function(element) { + var rules = {}; + var $element = $(element); + + for (var method in $.validator.methods) { + var value = $element.attr(method); + if (value) { + rules[method] = value; + } + } + + // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs + if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) { + delete rules.maxlength; + } + + return rules; + }, + + metadataRules: function(element) { + if (!$.metadata) return {}; + + var meta = $.data(element.form, 'validator').settings.meta; + return meta ? + $(element).metadata()[meta] : + $(element).metadata(); + }, + + staticRules: function(element) { + var rules = {}; + var validator = $.data(element.form, 'validator'); + if (validator.settings.rules) { + rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {}; + } + return rules; + }, + + normalizeRules: function(rules, element) { + // handle dependency check + $.each(rules, function(prop, val) { + // ignore rule when param is explicitly false, eg. required:false + if (val === false) { + delete rules[prop]; + return; + } + if (val.param || val.depends) { + var keepRule = true; + switch (typeof val.depends) { + case "string": + keepRule = !!$(val.depends, element.form).length; + break; + case "function": + keepRule = val.depends.call(element, element); + break; + } + if (keepRule) { + rules[prop] = val.param !== undefined ? val.param : true; + } else { + delete rules[prop]; + } + } + }); + + // evaluate parameters + $.each(rules, function(rule, parameter) { + rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter; + }); + + // clean number parameters + $.each(['minlength', 'maxlength', 'min', 'max'], function() { + if (rules[this]) { + rules[this] = Number(rules[this]); + } + }); + $.each(['rangelength', 'range'], function() { + if (rules[this]) { + rules[this] = [Number(rules[this][0]), Number(rules[this][1])]; + } + }); + + if ($.validator.autoCreateRanges) { + // auto-create ranges + if (rules.min && rules.max) { + rules.range = [rules.min, rules.max]; + delete rules.min; + delete rules.max; + } + if (rules.minlength && rules.maxlength) { + rules.rangelength = [rules.minlength, rules.maxlength]; + delete rules.minlength; + delete rules.maxlength; + } + } + + // To support custom messages in metadata ignore rule methods titled "messages" + if (rules.messages) { + delete rules.messages; + } + + return rules; + }, + + // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true} + normalizeRule: function(data) { + if( typeof data == "string" ) { + var transformed = {}; + $.each(data.split(/\s/), function() { + transformed[this] = true; + }); + data = transformed; + } + return data; + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/addMethod + addMethod: function(name, method, message) { + $.validator.methods[name] = method; + $.validator.messages[name] = message != undefined ? message : $.validator.messages[name]; + if (method.length < 3) { + $.validator.addClassRules(name, $.validator.normalizeRule(name)); + } + }, + + methods: { + + // http://docs.jquery.com/Plugins/Validation/Methods/required + required: function(value, element, param) { + // check if dependency is met + if ( !this.depend(param, element) ) + return "dependency-mismatch"; + switch( element.nodeName.toLowerCase() ) { + case 'select': + // could be an array for select-multiple or a string, both are fine this way + var val = $(element).val(); + return val && val.length > 0; + case 'input': + if ( this.checkable(element) ) + return this.getLength(value, element) > 0; + default: + return $.trim(value).length > 0; + } + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/remote + remote: function(value, element, param) { + if ( this.optional(element) ) + return "dependency-mismatch"; + + var previous = this.previousValue(element); + if (!this.settings.messages[element.name] ) + this.settings.messages[element.name] = {}; + previous.originalMessage = this.settings.messages[element.name].remote; + this.settings.messages[element.name].remote = previous.message; + + param = typeof param == "string" && {url:param} || param; + + if ( this.pending[element.name] ) { + return "pending"; + } + if ( previous.old === value ) { + return previous.valid; + } + + previous.old = value; + var validator = this; + this.startRequest(element); + var data = {}; + data[element.name] = value; + $.ajax($.extend(true, { + url: param, + mode: "abort", + port: "validate" + element.name, + dataType: "json", + data: data, + success: function(response) { + validator.settings.messages[element.name].remote = previous.originalMessage; + var valid = response === true; + if ( valid ) { + var submitted = validator.formSubmitted; + validator.prepareElement(element); + validator.formSubmitted = submitted; + validator.successList.push(element); + validator.showErrors(); + } else { + var errors = {}; + var message = response || validator.defaultMessage( element, "remote" ); + errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message; + validator.showErrors(errors); + } + previous.valid = valid; + validator.stopRequest(element, valid); + } + }, param)); + return "pending"; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/minlength + minlength: function(value, element, param) { + return this.optional(element) || this.getLength($.trim(value), element) >= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/maxlength + maxlength: function(value, element, param) { + return this.optional(element) || this.getLength($.trim(value), element) <= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/rangelength + rangelength: function(value, element, param) { + var length = this.getLength($.trim(value), element); + return this.optional(element) || ( length >= param[0] && length <= param[1] ); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/min + min: function( value, element, param ) { + return this.optional(element) || value >= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/max + max: function( value, element, param ) { + return this.optional(element) || value <= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/range + range: function( value, element, param ) { + return this.optional(element) || ( value >= param[0] && value <= param[1] ); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/email + email: function(value, element) { + // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/ + return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([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])))\.?$/i.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/url + url: function(value, element) { + // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/ + 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); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/date + date: function(value, element) { + return this.optional(element) || !/Invalid|NaN/.test(new Date(value)); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/dateISO + dateISO: function(value, element) { + return this.optional(element) || /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/number + number: function(value, element) { + return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/digits + digits: function(value, element) { + return this.optional(element) || /^\d+$/.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/creditcard + // based on http://en.wikipedia.org/wiki/Luhn + creditcard: function(value, element) { + if ( this.optional(element) ) + return "dependency-mismatch"; + // accept only digits and dashes + if (/[^0-9-]+/.test(value)) + return false; + var nCheck = 0, + nDigit = 0, + bEven = false; + + value = value.replace(/\D/g, ""); + + for (var n = value.length - 1; n >= 0; n--) { + var cDigit = value.charAt(n); + var nDigit = parseInt(cDigit, 10); + if (bEven) { + if ((nDigit *= 2) > 9) + nDigit -= 9; + } + nCheck += nDigit; + bEven = !bEven; + } + + return (nCheck % 10) == 0; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/accept + accept: function(value, element, param) { + param = typeof param == "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif"; + return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i")); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/equalTo + equalTo: function(value, element, param) { + // bind to the blur event of the target in order to revalidate whenever the target field is updated + // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead + var target = $(param).unbind(".validate-equalTo").bind("blur.validate-equalTo", function() { + $(element).valid(); + }); + return value == target.val(); + } + + } + +}); + +// deprecated, use $.validator.format instead +$.format = $.validator.format; + +})(jQuery); + +// ajax mode: abort +// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]}); +// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() +;(function($) { + var pendingRequests = {}; + // Use a prefilter if available (1.5+) + if ( $.ajaxPrefilter ) { + $.ajaxPrefilter(function(settings, _, xhr) { + var port = settings.port; + if (settings.mode == "abort") { + if ( pendingRequests[port] ) { + pendingRequests[port].abort(); + } + pendingRequests[port] = xhr; + } + }); + } else { + // Proxy ajax + var ajax = $.ajax; + $.ajax = function(settings) { + var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode, + port = ( "port" in settings ? settings : $.ajaxSettings ).port; + if (mode == "abort") { + if ( pendingRequests[port] ) { + pendingRequests[port].abort(); + } + return (pendingRequests[port] = ajax.apply(this, arguments)); + } + return ajax.apply(this, arguments); + }; + } +})(jQuery); + +// provides cross-browser focusin and focusout events +// IE has native support, in other browsers, use event caputuring (neither bubbles) + +// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation +// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target +;(function($) { + // only implement if not provided by jQuery core (since 1.4) + // TODO verify if jQuery 1.4's implementation is compatible with older jQuery special-event APIs + if (!jQuery.event.special.focusin && !jQuery.event.special.focusout && document.addEventListener) { + $.each({ + focus: 'focusin', + blur: 'focusout' + }, function( original, fix ){ + $.event.special[fix] = { + setup:function() { + this.addEventListener( original, handler, true ); + }, + teardown:function() { + this.removeEventListener( original, handler, true ); + }, + handler: function(e) { + arguments[0] = $.event.fix(e); + arguments[0].type = fix; + return $.event.handle.apply(this, arguments); + } + }; + function handler(e) { + e = $.event.fix(e); + e.type = fix; + return $.event.handle.call(this, e); + } + }); + }; + $.extend($.fn, { + validateDelegate: function(delegate, type, handler) { + return this.bind(type, function(event) { + var target = $(event.target); + if (target.is(delegate)) { + return handler.apply(target, arguments); + } + }); + } + }); +})(jQuery); diff --git a/src/Test/packages/jQuery.Validation.1.8.0/Content/Scripts/jquery.validate.min.js b/src/Test/packages/jQuery.Validation.1.8.0/Content/Scripts/jquery.validate.min.js new file mode 100644 index 000000000..b07c2ab2d --- /dev/null +++ b/src/Test/packages/jQuery.Validation.1.8.0/Content/Scripts/jquery.validate.min.js @@ -0,0 +1,53 @@ +/** +* Note: While Microsoft is not the author of this file, Microsoft is +* offering you a license subject to the terms of the Microsoft Software +* License Terms for Microsoft ASP.NET Model View Controller 3. +* Microsoft reserves all other rights. The notices below are provided +* for informational purposes only and are not the license terms under +* which Microsoft distributed this file. +* +* jQuery Validation Plugin 1.8.0 +* +* http://bassistance.de/jquery-plugins/jquery-plugin-validation/ +* http://docs.jquery.com/Plugins/Validation +* +* Copyright (c) 2006 - 2011 Jörn Zaefferer +*/ +(function(c){c.extend(c.fn,{validate:function(a){if(this.length){var b=c.data(this[0],"validator");if(b)return b;b=new c.validator(a,this[0]);c.data(this[0],"validator",b);if(b.settings.onsubmit){this.find("input, button").filter(".cancel").click(function(){b.cancelSubmit=true});b.settings.submitHandler&&this.find("input, button").filter(":submit").click(function(){b.submitButton=this});this.submit(function(d){function e(){if(b.settings.submitHandler){if(b.submitButton)var f=c("").attr("name", +b.submitButton.name).val(b.submitButton.value).appendTo(b.currentForm);b.settings.submitHandler.call(b,b.currentForm);b.submitButton&&f.remove();return false}return true}b.settings.debug&&d.preventDefault();if(b.cancelSubmit){b.cancelSubmit=false;return e()}if(b.form()){if(b.pendingRequest){b.formSubmitted=true;return false}return e()}else{b.focusInvalid();return false}})}return b}else a&&a.debug&&window.console&&console.warn("nothing selected, can't validate, returning nothing")},valid:function(){if(c(this[0]).is("form"))return this.validate().form(); +else{var a=true,b=c(this[0].form).validate();this.each(function(){a&=b.element(this)});return a}},removeAttrs:function(a){var b={},d=this;c.each(a.split(/\s/),function(e,f){b[f]=d.attr(f);d.removeAttr(f)});return b},rules:function(a,b){var d=this[0];if(a){var e=c.data(d.form,"validator").settings,f=e.rules,g=c.validator.staticRules(d);switch(a){case "add":c.extend(g,c.validator.normalizeRule(b));f[d.name]=g;if(b.messages)e.messages[d.name]=c.extend(e.messages[d.name],b.messages);break;case "remove":if(!b){delete f[d.name]; +return g}var h={};c.each(b.split(/\s/),function(j,i){h[i]=g[i];delete g[i]});return h}}d=c.validator.normalizeRules(c.extend({},c.validator.metadataRules(d),c.validator.classRules(d),c.validator.attributeRules(d),c.validator.staticRules(d)),d);if(d.required){e=d.required;delete d.required;d=c.extend({required:e},d)}return d}});c.extend(c.expr[":"],{blank:function(a){return!c.trim(""+a.value)},filled:function(a){return!!c.trim(""+a.value)},unchecked:function(a){return!a.checked}});c.validator=function(a, +b){this.settings=c.extend(true,{},c.validator.defaults,a);this.currentForm=b;this.init()};c.validator.format=function(a,b){if(arguments.length==1)return function(){var d=c.makeArray(arguments);d.unshift(a);return c.validator.format.apply(this,d)};if(arguments.length>2&&b.constructor!=Array)b=c.makeArray(arguments).slice(1);if(b.constructor!=Array)b=[b];c.each(b,function(d,e){a=a.replace(RegExp("\\{"+d+"\\}","g"),e)});return a};c.extend(c.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error", +validClass:"valid",errorElement:"label",focusInvalid:true,errorContainer:c([]),errorLabelContainer:c([]),onsubmit:true,ignore:[],ignoreTitle:false,onfocusin:function(a){this.lastActive=a;if(this.settings.focusCleanup&&!this.blockFocusCleanup){this.settings.unhighlight&&this.settings.unhighlight.call(this,a,this.settings.errorClass,this.settings.validClass);this.addWrapper(this.errorsFor(a)).hide()}},onfocusout:function(a){if(!this.checkable(a)&&(a.name in this.submitted||!this.optional(a)))this.element(a)}, +onkeyup:function(a){if(a.name in this.submitted||a==this.lastElement)this.element(a)},onclick:function(a){if(a.name in this.submitted)this.element(a);else a.parentNode.name in this.submitted&&this.element(a.parentNode)},highlight:function(a,b,d){c(a).addClass(b).removeClass(d)},unhighlight:function(a,b,d){c(a).removeClass(b).addClass(d)}},setDefaults:function(a){c.extend(c.validator.defaults,a)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.", +url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date (ISO).",number:"Please enter a valid number.",digits:"Please enter only digits.",creditcard:"Please enter a valid credit card number.",equalTo:"Please enter the same value again.",accept:"Please enter a value with a valid extension.",maxlength:c.validator.format("Please enter no more than {0} characters."),minlength:c.validator.format("Please enter at least {0} characters."),rangelength:c.validator.format("Please enter a value between {0} and {1} characters long."), +range:c.validator.format("Please enter a value between {0} and {1}."),max:c.validator.format("Please enter a value less than or equal to {0}."),min:c.validator.format("Please enter a value greater than or equal to {0}.")},autoCreateRanges:false,prototype:{init:function(){function a(e){var f=c.data(this[0].form,"validator");e="on"+e.type.replace(/^validate/,"");f.settings[e]&&f.settings[e].call(f,this[0])}this.labelContainer=c(this.settings.errorLabelContainer);this.errorContext=this.labelContainer.length&& +this.labelContainer||c(this.currentForm);this.containers=c(this.settings.errorContainer).add(this.settings.errorLabelContainer);this.submitted={};this.valueCache={};this.pendingRequest=0;this.pending={};this.invalid={};this.reset();var b=this.groups={};c.each(this.settings.groups,function(e,f){c.each(f.split(/\s/),function(g,h){b[h]=e})});var d=this.settings.rules;c.each(d,function(e,f){d[e]=c.validator.normalizeRule(f)});c(this.currentForm).validateDelegate(":text, :password, :file, select, textarea", +"focusin focusout keyup",a).validateDelegate(":radio, :checkbox, select, option","click",a);this.settings.invalidHandler&&c(this.currentForm).bind("invalid-form.validate",this.settings.invalidHandler)},form:function(){this.checkForm();c.extend(this.submitted,this.errorMap);this.invalid=c.extend({},this.errorMap);this.valid()||c(this.currentForm).triggerHandler("invalid-form",[this]);this.showErrors();return this.valid()},checkForm:function(){this.prepareForm();for(var a=0,b=this.currentElements=this.elements();b[a];a++)this.check(b[a]); +return this.valid()},element:function(a){this.lastElement=a=this.clean(a);this.prepareElement(a);this.currentElements=c(a);var b=this.check(a);if(b)delete this.invalid[a.name];else this.invalid[a.name]=true;if(!this.numberOfInvalids())this.toHide=this.toHide.add(this.containers);this.showErrors();return b},showErrors:function(a){if(a){c.extend(this.errorMap,a);this.errorList=[];for(var b in a)this.errorList.push({message:a[b],element:this.findByName(b)[0]});this.successList=c.grep(this.successList, +function(d){return!(d.name in a)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){c.fn.resetForm&&c(this.currentForm).resetForm();this.submitted={};this.prepareForm();this.hideErrors();this.elements().removeClass(this.settings.errorClass)},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(a){var b=0,d;for(d in a)b++;return b},hideErrors:function(){this.addWrapper(this.toHide).hide()}, +valid:function(){return this.size()==0},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{c(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(a){}},findLastActive:function(){var a=this.lastActive;return a&&c.grep(this.errorList,function(b){return b.element.name==a.name}).length==1&&a},elements:function(){var a=this,b={};return c([]).add(this.currentForm.elements).filter(":input").not(":submit, :reset, :image, [disabled]").not(this.settings.ignore).filter(function(){!this.name&& +a.settings.debug&&window.console&&console.error("%o has no name assigned",this);if(this.name in b||!a.objectLength(c(this).rules()))return false;return b[this.name]=true})},clean:function(a){return c(a)[0]},errors:function(){return c(this.settings.errorElement+"."+this.settings.errorClass,this.errorContext)},reset:function(){this.successList=[];this.errorList=[];this.errorMap={};this.toShow=c([]);this.toHide=c([]);this.currentElements=c([])},prepareForm:function(){this.reset();this.toHide=this.errors().add(this.containers)}, +prepareElement:function(a){this.reset();this.toHide=this.errorsFor(a)},check:function(a){a=this.clean(a);if(this.checkable(a))a=this.findByName(a.name).not(this.settings.ignore)[0];var b=c(a).rules(),d=false,e;for(e in b){var f={method:e,parameters:b[e]};try{var g=c.validator.methods[e].call(this,a.value.replace(/\r/g,""),a,f.parameters);if(g=="dependency-mismatch")d=true;else{d=false;if(g=="pending"){this.toHide=this.toHide.not(this.errorsFor(a));return}if(!g){this.formatAndAdd(a,f);return false}}}catch(h){this.settings.debug&& +window.console&&console.log("exception occured when checking element "+a.id+", check the '"+f.method+"' method",h);throw h;}}if(!d){this.objectLength(b)&&this.successList.push(a);return true}},customMetaMessage:function(a,b){if(c.metadata){var d=this.settings.meta?c(a).metadata()[this.settings.meta]:c(a).metadata();return d&&d.messages&&d.messages[b]}},customMessage:function(a,b){var d=this.settings.messages[a];return d&&(d.constructor==String?d:d[b])},findDefined:function(){for(var a=0;aWarning: No message defined for "+a.name+"")},formatAndAdd:function(a,b){var d=this.defaultMessage(a,b.method),e=/\$?\{(\d+)\}/g;if(typeof d=="function")d=d.call(this,b.parameters,a);else if(e.test(d))d=jQuery.format(d.replace(e,"{$1}"),b.parameters);this.errorList.push({message:d, +element:a});this.errorMap[a.name]=d;this.submitted[a.name]=d},addWrapper:function(a){if(this.settings.wrapper)a=a.add(a.parent(this.settings.wrapper));return a},defaultShowErrors:function(){for(var a=0;this.errorList[a];a++){var b=this.errorList[a];this.settings.highlight&&this.settings.highlight.call(this,b.element,this.settings.errorClass,this.settings.validClass);this.showLabel(b.element,b.message)}if(this.errorList.length)this.toShow=this.toShow.add(this.containers);if(this.settings.success)for(a= +0;this.successList[a];a++)this.showLabel(this.successList[a]);if(this.settings.unhighlight){a=0;for(b=this.validElements();b[a];a++)this.settings.unhighlight.call(this,b[a],this.settings.errorClass,this.settings.validClass)}this.toHide=this.toHide.not(this.toShow);this.hideErrors();this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return c(this.errorList).map(function(){return this.element})},showLabel:function(a, +b){var d=this.errorsFor(a);if(d.length){d.removeClass().addClass(this.settings.errorClass);d.attr("generated")&&d.html(b)}else{d=c("<"+this.settings.errorElement+"/>").attr({"for":this.idOrName(a),generated:true}).addClass(this.settings.errorClass).html(b||"");if(this.settings.wrapper)d=d.hide().show().wrap("<"+this.settings.wrapper+"/>").parent();this.labelContainer.append(d).length||(this.settings.errorPlacement?this.settings.errorPlacement(d,c(a)):d.insertAfter(a))}if(!b&&this.settings.success){d.text(""); +typeof this.settings.success=="string"?d.addClass(this.settings.success):this.settings.success(d)}this.toShow=this.toShow.add(d)},errorsFor:function(a){var b=this.idOrName(a);return this.errors().filter(function(){return c(this).attr("for")==b})},idOrName:function(a){return this.groups[a.name]||(this.checkable(a)?a.name:a.id||a.name)},checkable:function(a){return/radio|checkbox/i.test(a.type)},findByName:function(a){var b=this.currentForm;return c(document.getElementsByName(a)).map(function(d,e){return e.form== +b&&e.name==a&&e||null})},getLength:function(a,b){switch(b.nodeName.toLowerCase()){case "select":return c("option:selected",b).length;case "input":if(this.checkable(b))return this.findByName(b.name).filter(":checked").length}return a.length},depend:function(a,b){return this.dependTypes[typeof a]?this.dependTypes[typeof a](a,b):true},dependTypes:{"boolean":function(a){return a},string:function(a,b){return!!c(a,b.form).length},"function":function(a,b){return a(b)}},optional:function(a){return!c.validator.methods.required.call(this, +c.trim(a.value),a)&&"dependency-mismatch"},startRequest:function(a){if(!this.pending[a.name]){this.pendingRequest++;this.pending[a.name]=true}},stopRequest:function(a,b){this.pendingRequest--;if(this.pendingRequest<0)this.pendingRequest=0;delete this.pending[a.name];if(b&&this.pendingRequest==0&&this.formSubmitted&&this.form()){c(this.currentForm).submit();this.formSubmitted=false}else if(!b&&this.pendingRequest==0&&this.formSubmitted){c(this.currentForm).triggerHandler("invalid-form",[this]);this.formSubmitted= +false}},previousValue:function(a){return c.data(a,"previousValue")||c.data(a,"previousValue",{old:null,valid:true,message:this.defaultMessage(a,"remote")})}},classRuleSettings:{required:{required:true},email:{email:true},url:{url:true},date:{date:true},dateISO:{dateISO:true},dateDE:{dateDE:true},number:{number:true},numberDE:{numberDE:true},digits:{digits:true},creditcard:{creditcard:true}},addClassRules:function(a,b){a.constructor==String?this.classRuleSettings[a]=b:c.extend(this.classRuleSettings, +a)},classRules:function(a){var b={};(a=c(a).attr("class"))&&c.each(a.split(" "),function(){this in c.validator.classRuleSettings&&c.extend(b,c.validator.classRuleSettings[this])});return b},attributeRules:function(a){var b={};a=c(a);for(var d in c.validator.methods){var e=a.attr(d);if(e)b[d]=e}b.maxlength&&/-1|2147483647|524288/.test(b.maxlength)&&delete b.maxlength;return b},metadataRules:function(a){if(!c.metadata)return{};var b=c.data(a.form,"validator").settings.meta;return b?c(a).metadata()[b]: +c(a).metadata()},staticRules:function(a){var b={},d=c.data(a.form,"validator");if(d.settings.rules)b=c.validator.normalizeRule(d.settings.rules[a.name])||{};return b},normalizeRules:function(a,b){c.each(a,function(d,e){if(e===false)delete a[d];else if(e.param||e.depends){var f=true;switch(typeof e.depends){case "string":f=!!c(e.depends,b.form).length;break;case "function":f=e.depends.call(b,b)}if(f)a[d]=e.param!==undefined?e.param:true;else delete a[d]}});c.each(a,function(d,e){a[d]=c.isFunction(e)? +e(b):e});c.each(["minlength","maxlength","min","max"],function(){if(a[this])a[this]=Number(a[this])});c.each(["rangelength","range"],function(){if(a[this])a[this]=[Number(a[this][0]),Number(a[this][1])]});if(c.validator.autoCreateRanges){if(a.min&&a.max){a.range=[a.min,a.max];delete a.min;delete a.max}if(a.minlength&&a.maxlength){a.rangelength=[a.minlength,a.maxlength];delete a.minlength;delete a.maxlength}}a.messages&&delete a.messages;return a},normalizeRule:function(a){if(typeof a=="string"){var b= +{};c.each(a.split(/\s/),function(){b[this]=true});a=b}return a},addMethod:function(a,b,d){c.validator.methods[a]=b;c.validator.messages[a]=d!=undefined?d:c.validator.messages[a];b.length<3&&c.validator.addClassRules(a,c.validator.normalizeRule(a))},methods:{required:function(a,b,d){if(!this.depend(d,b))return"dependency-mismatch";switch(b.nodeName.toLowerCase()){case "select":return(a=c(b).val())&&a.length>0;case "input":if(this.checkable(b))return this.getLength(a,b)>0;default:return c.trim(a).length> +0}},remote:function(a,b,d){if(this.optional(b))return"dependency-mismatch";var e=this.previousValue(b);this.settings.messages[b.name]||(this.settings.messages[b.name]={});e.originalMessage=this.settings.messages[b.name].remote;this.settings.messages[b.name].remote=e.message;d=typeof d=="string"&&{url:d}||d;if(this.pending[b.name])return"pending";if(e.old===a)return e.valid;e.old=a;var f=this;this.startRequest(b);var g={};g[b.name]=a;c.ajax(c.extend(true,{url:d,mode:"abort",port:"validate"+b.name, +dataType:"json",data:g,success:function(h){f.settings.messages[b.name].remote=e.originalMessage;var j=h===true;if(j){var i=f.formSubmitted;f.prepareElement(b);f.formSubmitted=i;f.successList.push(b);f.showErrors()}else{i={};h=h||f.defaultMessage(b,"remote");i[b.name]=e.message=c.isFunction(h)?h(a):h;f.showErrors(i)}e.valid=j;f.stopRequest(b,j)}},d));return"pending"},minlength:function(a,b,d){return this.optional(b)||this.getLength(c.trim(a),b)>=d},maxlength:function(a,b,d){return this.optional(b)|| +this.getLength(c.trim(a),b)<=d},rangelength:function(a,b,d){a=this.getLength(c.trim(a),b);return this.optional(b)||a>=d[0]&&a<=d[1]},min:function(a,b,d){return this.optional(b)||a>=d},max:function(a,b,d){return this.optional(b)||a<=d},range:function(a,b,d){return this.optional(b)||a>=d[0]&&a<=d[1]},email:function(a,b){return this.optional(b)||/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([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])))\.?$/i.test(a)}, +url:function(a,b){return this.optional(b)||/^(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(a)}, +date:function(a,b){return this.optional(b)||!/Invalid|NaN/.test(new Date(a))},dateISO:function(a,b){return this.optional(b)||/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(a)},number:function(a,b){return this.optional(b)||/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(a)},digits:function(a,b){return this.optional(b)||/^\d+$/.test(a)},creditcard:function(a,b){if(this.optional(b))return"dependency-mismatch";if(/[^0-9-]+/.test(a))return false;var d=0,e=0,f=false;a=a.replace(/\D/g,"");for(var g=a.length-1;g>= +0;g--){e=a.charAt(g);e=parseInt(e,10);if(f)if((e*=2)>9)e-=9;d+=e;f=!f}return d%10==0},accept:function(a,b,d){d=typeof d=="string"?d.replace(/,/g,"|"):"png|jpe?g|gif";return this.optional(b)||a.match(RegExp(".("+d+")$","i"))},equalTo:function(a,b,d){d=c(d).unbind(".validate-equalTo").bind("blur.validate-equalTo",function(){c(b).valid()});return a==d.val()}}});c.format=c.validator.format})(jQuery); +(function(c){var a={};if(c.ajaxPrefilter)c.ajaxPrefilter(function(d,e,f){e=d.port;if(d.mode=="abort"){a[e]&&a[e].abort();a[e]=f}});else{var b=c.ajax;c.ajax=function(d){var e=("port"in d?d:c.ajaxSettings).port;if(("mode"in d?d:c.ajaxSettings).mode=="abort"){a[e]&&a[e].abort();return a[e]=b.apply(this,arguments)}return b.apply(this,arguments)}}})(jQuery); +(function(c){!jQuery.event.special.focusin&&!jQuery.event.special.focusout&&document.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.handle.call(this,e)}c.event.special[b]={setup:function(){this.addEventListener(a,d,true)},teardown:function(){this.removeEventListener(a,d,true)},handler:function(e){arguments[0]=c.event.fix(e);arguments[0].type=b;return c.event.handle.apply(this,arguments)}}});c.extend(c.fn,{validateDelegate:function(a, +b,d){return this.bind(b,function(e){var f=c(e.target);if(f.is(a))return d.apply(f,arguments)})}})})(jQuery); diff --git a/src/Test/packages/jQuery.Validation.1.8.0/jQuery.Validation.1.8.0.nupkg b/src/Test/packages/jQuery.Validation.1.8.0/jQuery.Validation.1.8.0.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..3a381a5b3f15dccc1ac37cbda49c7c409a99b3dd GIT binary patch literal 35004 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 i|F2%)pQ|?xMEXxYK~3@A{kvr7z&` + + + \ No newline at end of file

    + To learn more about ASP.NET MVC visit http://asp.net/mvc. +