diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9d4bf1c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,28 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{cs,svc,asax,aspx,cshtml,csproj,sln}] +charset = utf-8-bom + +[*.{config,csproj,nuspec,xml}] +indent_size = 2 +insert_final_newline = false + +[*.sln] +indent_style = tab + +[*.md] +trim_trailing_whitespace = false + +# Ignore these files +[{LICENSE,build/database/*,src/alloy/App_Data/**,src/alloy/modulesbin/**,src/alloy/obj/**,src/alloy/Static/**}] +indent_style = unset +indent_size = unset +trim_trailing_whitespace = unset +insert_final_newline = unset diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..0d84e23 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,42 @@ +## Set default behavior to automatically normalize line endings. +* text=auto + +## Visual Studio and .NET text files +*.ascx text +*.aspx text +*.cmd text +*.config text +*.cs text diff=csharp +*.cshtml text +*.csproj text eol=crlf +*.master text +*.msbuild text +*.ps1 text +*.psm1 text +*.sln text eol=crlf +*.sql text +*.targets text +*.transform text +*.xml text + +## Common web text files +*.css text +*.htm text +*.html text +*.js text +*.less text +*.md text + +## Bash and Linux text files +*.sh text eol=lf + +## Visual Studio and .NET binary files +*.dll binary +*.snk binary + +## Common web binary files +*.gif binary +*.ico binary +*.jpeg binary +*.jpg binary +*.png binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f7e2dbb --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +## Repository specific files + +App_Code/ +App_Data/ + +License.config + +## Ignore Visual Studio temporary files and build results. + +# User-specific files +*.user + +# Build results +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ + +# NuGet Packages +[Pp]ackages/ + +.idea/ +.vscode + +node_modules/ + +*.nupkg +episerver-labs-block-enhancements.zip diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..28f12c7 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# EPiServer Labs - Block Enhancements diff --git a/build.cmd b/build.cmd new file mode 100644 index 0000000..0ae1af6 --- /dev/null +++ b/build.cmd @@ -0,0 +1 @@ +CALL msbuild diff --git a/build/Templates.targets b/build/Templates.targets new file mode 100644 index 0000000..99352b9 --- /dev/null +++ b/build/Templates.targets @@ -0,0 +1,31 @@ + + + + + + + + CopyTemplatesSourceFiles;ReplaceNamespacesSourceFiles;$(BuildDependsOn) + $(CoreCleanDependsOn);CleanTemplatesSourceFiles + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/database/Alloy.mdf b/build/database/Alloy.mdf new file mode 100644 index 0000000..7bc638f Binary files /dev/null and b/build/database/Alloy.mdf differ diff --git a/build/database/DefaultSiteContent.episerverdata b/build/database/DefaultSiteContent.episerverdata new file mode 100644 index 0000000..b360d87 Binary files /dev/null and b/build/database/DefaultSiteContent.episerverdata differ diff --git a/build/tools/EPiServer.Build.Tasks.dll b/build/tools/EPiServer.Build.Tasks.dll new file mode 100644 index 0000000..9d0f6ef Binary files /dev/null and b/build/tools/EPiServer.Build.Tasks.dll differ diff --git a/build/transformers/AlloyMvc.Views.web.config.transform b/build/transformers/AlloyMvc.Views.web.config.transform new file mode 100644 index 0000000..ca9bf4f --- /dev/null +++ b/build/transformers/AlloyMvc.Views.web.config.transform @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/build/transformers/AlloyMvc.web.config.transform b/build/transformers/AlloyMvc.web.config.transform new file mode 100644 index 0000000..ebe787d --- /dev/null +++ b/build/transformers/AlloyMvc.web.config.transform @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/transformers/web.config.install.xdt b/build/transformers/web.config.install.xdt new file mode 100644 index 0000000..c11102a --- /dev/null +++ b/build/transformers/web.config.install.xdt @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/episerver-labs-block-enhancements.sln b/episerver-labs-block-enhancements.sln new file mode 100644 index 0000000..3de2e34 --- /dev/null +++ b/episerver-labs-block-enhancements.sln @@ -0,0 +1,54 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.271 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "alloy", "src\alloy\Alloy.Mvc.Template.csproj", "{3D79ADE5-DADB-47D2-933D-E98F9773AFAD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F856CAEC-B3F9-4320-B39D-E8F2EB8F6111}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{A1272902-1CD0-4507-9714-CB3AE96E78FD}" + ProjectSection(SolutionItems) = preProject + build\Templates.targets = build\Templates.targets + .editorconfig = .editorconfig + .gitattributes = .gitattributes + .gitignore = .gitignore + build.cmd = build.cmd + iisexpress.cmd = iisexpress.cmd + LICENSE = LICENSE + pack.cmd = pack.cmd + pack.ps1 = pack.ps1 + README.md = README.md + setup.cmd = setup.cmd + site.cmd = site.cmd + version.cs = version.cs + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPiServer.Labs.BlockEnhancements", "src\episerver-labs-block-enhancements\EPiServer.Labs.BlockEnhancements.csproj", "{7D3CB0B4-BF55-4577-ABF2-D83F8EA5D49F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3D79ADE5-DADB-47D2-933D-E98F9773AFAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D79ADE5-DADB-47D2-933D-E98F9773AFAD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D79ADE5-DADB-47D2-933D-E98F9773AFAD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D79ADE5-DADB-47D2-933D-E98F9773AFAD}.Release|Any CPU.Build.0 = Release|Any CPU + {7D3CB0B4-BF55-4577-ABF2-D83F8EA5D49F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7D3CB0B4-BF55-4577-ABF2-D83F8EA5D49F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D3CB0B4-BF55-4577-ABF2-D83F8EA5D49F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7D3CB0B4-BF55-4577-ABF2-D83F8EA5D49F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {3D79ADE5-DADB-47D2-933D-E98F9773AFAD} = {F856CAEC-B3F9-4320-B39D-E8F2EB8F6111} + {7D3CB0B4-BF55-4577-ABF2-D83F8EA5D49F} = {F856CAEC-B3F9-4320-B39D-E8F2EB8F6111} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {31F10C96-F924-4A0A-9B12-36A09C66A0B3} + EndGlobalSection +EndGlobal diff --git a/iisexpress.cmd b/iisexpress.cmd new file mode 100644 index 0000000..c4d4328 --- /dev/null +++ b/iisexpress.cmd @@ -0,0 +1 @@ +CALL "C:\Program Files\IIS Express\iisexpress.exe" /path:%~dp0src\alloy diff --git a/pack.cmd b/pack.cmd new file mode 100644 index 0000000..6a00f3d --- /dev/null +++ b/pack.cmd @@ -0,0 +1 @@ +powershell ./pack.ps1 \ No newline at end of file diff --git a/pack.ps1 b/pack.ps1 new file mode 100644 index 0000000..db9b2d1 --- /dev/null +++ b/pack.ps1 @@ -0,0 +1,25 @@ +$defaultVersion="1.0.0" +function ZipCurrentModule +{ + Param ([String]$moduleName) + Robocopy.exe $defaultVersion\ $version\ /S + ((Get-Content -Path module.config -Raw) -Replace $defaultVersion, $version ) | Set-Content -Path module.config + 7z a "$moduleName.zip" $version Views module.config + git checkout module.config + Remove-Item $version -Force -Recurse +} + +msbuild /p:Configuration=Release +npm run build --prefix ./src/ui + +$fullVersion=[System.Reflection.Assembly]::LoadFrom("src\alloy\bin\EPiServer.Labs.BlockEnhancements.dll").GetName().Version +$version="$($fullVersion.major).$($fullVersion.minor).$($fullVersion.build)" +Write-Host "Creating nuget with $version version" + +Set-Location src\alloy\modules\_protected\episerver-labs-block-enhancements +ZipCurrentModule -moduleName episerver-labs-block-enhancements + +Set-Location ..\..\..\ +nuget pack EPiServer.Labs.BlockEnhancements.nuspec -Version $version +Set-Location ..\..\ +Move-Item src\alloy\EPiServer.Labs.BlockEnhancements.$version.nupkg EPiServer.Labs.BlockEnhancements.$version.nupkg -Force diff --git a/setup.cmd b/setup.cmd new file mode 100644 index 0000000..77267f5 --- /dev/null +++ b/setup.cmd @@ -0,0 +1,16 @@ +@ECHO OFF + +SET AlloyMVC=src\alloy + +IF EXIST %AlloyMVC%\App_Data ( + ECHO Remove all files from the app data folder + DEL %AlloyMVC%\App_Data\*.* /F /Q || Exit /B 1 +) ELSE ( + MKDIR %AlloyMVC%\App_Data || Exit /B 1 +) + +REM Copy the database files to the site. +XCOPY /y/i build\Database\DefaultSiteContent.episerverdata %AlloyMVC%\App_Data\ || Exit /B 1 +XCOPY /y/i/k build\database\Alloy.mdf %AlloyMVC%\App_Data\ || Exit /B 1 + +EXIT /B %ERRORLEVEL% diff --git a/site.cmd b/site.cmd new file mode 100644 index 0000000..7bd4836 --- /dev/null +++ b/site.cmd @@ -0,0 +1,2 @@ +CALL build.cmd +CALL iisexpress.cmd diff --git a/src/alloy/Alloy.Mvc.Template.csproj b/src/alloy/Alloy.Mvc.Template.csproj new file mode 100644 index 0000000..ff722e1 --- /dev/null +++ b/src/alloy/Alloy.Mvc.Template.csproj @@ -0,0 +1,564 @@ + + + + + Debug + AnyCPU + + + 2.0 + {3D79ADE5-DADB-47D2-933D-E98F9773AFAD} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + AlloyTemplates + AlloyMvcTemplates + v4.6.1 + true + + + 4.0 + + + + + + ..\..\ + true + SAK + SAK + SAK + SAK + + true + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + true + false + + + pdbonly + true + bin\ + TRACE + prompt + 4 + true + false + + + + ..\..\packages\Antlr.3.5.0.2\lib\Antlr3.Runtime.dll + True + + + ..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + True + + + ..\..\packages\Castle.Windsor.4.1.0\lib\net45\Castle.Windsor.dll + True + + + ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll + True + + + ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll + True + + + ..\..\packages\EPiServer.CMS.Core.11.9.2\lib\net461\EPiServer.dll + + + ..\..\packages\EPiServer.Framework.11.9.2\lib\net461\EPiServer.ApplicationModules.dll + + + ..\..\packages\EPiServer.CMS.AspNet.11.9.2\lib\net461\EPiServer.Cms.AspNet.dll + + + ..\..\packages\EPiServer.CMS.UI.Core.11.5.3\lib\net461\EPiServer.Cms.Shell.UI.dll + + + ..\..\packages\EPiServer.CMS.TinyMce.2.6.5\lib\net461\EPiServer.Cms.TinyMce.dll + + + ..\..\packages\EPiServer.CMS.UI.AspNetIdentity.11.5.3\lib\net461\EPiServer.Cms.UI.AspNetIdentity.dll + + + ..\..\packages\EPiServer.CMS.AspNet.11.9.2\lib\net461\EPiServer.Configuration.dll + + + ..\..\packages\EPiServer.Framework.11.9.2\lib\net461\EPiServer.Data.dll + + + ..\..\packages\EPiServer.Framework.11.9.2\lib\net461\EPiServer.Data.Cache.dll + + + ..\..\packages\EPiServer.CMS.Core.11.9.2\lib\net461\EPiServer.Enterprise.dll + + + ..\..\packages\EPiServer.Framework.11.9.2\lib\net461\EPiServer.Events.dll + + + ..\..\packages\EPiServer.Framework.11.9.2\lib\net461\EPiServer.Framework.dll + + + ..\..\packages\EPiServer.Framework.AspNet.11.9.2\lib\net461\EPiServer.Framework.AspNet.dll + + + ..\..\packages\EPiServer.CMS.AspNet.11.9.2\lib\net461\EPiServer.ImageLibrary.dll + + + ..\..\packages\EPiServer.Framework.11.9.2\lib\net461\EPiServer.Licensing.dll + + + ..\..\packages\EPiServer.CMS.Core.11.9.2\lib\net461\EPiServer.LinkAnalyzer.dll + + + ..\..\packages\EPiServer.Search.Cms.9.0.1\lib\net461\EPiServer.Search.Cms.dll + True + + + ..\..\packages\EPiServer.Search.9.0.1\lib\net461\EPiServer.Search.IndexingService.dll + True + + + ..\..\packages\EPiServer.ServiceLocation.StructureMap.2.0.1\lib\net461\EPiServer.ServiceLocation.StructureMap.dll + + + ..\..\packages\EPiServer.CMS.UI.Core.11.5.3\lib\net461\EPiServer.Shell.dll + + + ..\..\packages\EPiServer.CMS.UI.Core.11.5.3\lib\net461\EPiServer.Shell.UI.dll + + + ..\..\packages\EPiServer.CMS.UI.Core.11.5.3\lib\net461\EPiServer.UI.dll + + + ..\..\packages\EPiServer.CMS.AspNet.11.9.2\lib\net461\EPiServer.Web.WebControls.dll + + + ..\..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll + True + + + ..\..\packages\Lucene.Net.3.0.3\lib\NET40\Lucene.Net.dll + True + + + ..\..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll + True + + + ..\..\packages\Microsoft.AspNet.Identity.EntityFramework.2.2.1\lib\net45\Microsoft.AspNet.Identity.EntityFramework.dll + True + + + ..\..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll + True + + + + ..\..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll + True + + + ..\..\packages\Microsoft.Owin.Host.SystemWeb.3.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll + True + + + ..\..\packages\Microsoft.Owin.Security.3.0.0\lib\net45\Microsoft.Owin.Security.dll + True + + + ..\..\packages\Microsoft.Owin.Security.Cookies.3.0.0\lib\net45\Microsoft.Owin.Security.Cookies.dll + True + + + ..\..\packages\Microsoft.Owin.Security.OAuth.3.0.0\lib\net45\Microsoft.Owin.Security.OAuth.dll + True + + + ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + True + + + ..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + True + + + ..\..\packages\Owin.1.0\lib\net40\Owin.dll + True + + + ..\..\packages\StructureMap.4.5.2\lib\net45\StructureMap.dll + + + ..\..\packages\structuremap-signed.3.1.9.463\lib\net40\StructureMap.Net4.dll + + + ..\..\packages\structuremap.web.4.0.0.315\lib\net40\StructureMap.Web.dll + + + ..\..\packages\System.ComponentModel.Annotations.4.4.0\lib\net461\System.ComponentModel.Annotations.dll + + + + + ..\..\packages\System.Data.SqlClient.4.4.0\lib\net461\System.Data.SqlClient.dll + + + + + + ..\..\packages\System.Security.AccessControl.4.4.0\lib\net461\System.Security.AccessControl.dll + + + ..\..\packages\System.Security.Cryptography.Xml.4.4.2\lib\net461\System.Security.Cryptography.Xml.dll + + + ..\..\packages\System.Security.Permissions.4.4.0\lib\net461\System.Security.Permissions.dll + + + ..\..\packages\System.Security.Principal.Windows.4.4.0\lib\net461\System.Security.Principal.Windows.dll + + + ..\..\packages\System.Threading.AccessControl.4.4.0\lib\net461\System.Threading.AccessControl.dll + + + ..\..\packages\Microsoft.Tpl.Dataflow.4.5.24\lib\portable-net45+win8+wpa81\System.Threading.Tasks.Dataflow.dll + True + + + + ..\..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll + + + + + + + + + + + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + True + + + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + True + + + ..\..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll + True + + + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + True + + + + + + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + True + + + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + True + + + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + True + + + + + + + + ..\..\packages\WebGrease.1.6.0\lib\WebGrease.dll + True + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Global.asax + + + + + + + + + + + + + + + + + + + + + + + + + + + + Code + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + + + + + + + + Designer + + + + + Designer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + + + + + + + + + Designer + + + + + + + + + + + + Designer + + + Designer + + + Designer + + + Designer + + + web.config + + + web.config + + + + + Designer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + + + + + + + + + + + + + {7D3CB0B4-BF55-4577-ABF2-D83F8EA5D49F} + episerver-labs-block-enhancements + + + \ No newline at end of file diff --git a/src/alloy/Business/AdministratorRegistrationPage.cs b/src/alloy/Business/AdministratorRegistrationPage.cs new file mode 100644 index 0000000..e9bab95 --- /dev/null +++ b/src/alloy/Business/AdministratorRegistrationPage.cs @@ -0,0 +1,82 @@ +using EPiServer.ServiceLocation; +using EPiServer.Shell.Security; +using Owin; +using System; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; + +namespace AlloyTemplates +{ + public static class AdministratorRegistrationPage + { + private static Func _isLocalRequest = () => false; + + private static Lazy _isAnyUserRegistered = new Lazy(() => false); + + private static bool? _isEnabled = null; + + public static bool IsEnabled + { + get + { + if (_isEnabled.HasValue) + { + return _isEnabled.Value; + } + + var showUserRegistration = _isLocalRequest() && !_isAnyUserRegistered.Value; + if (!showUserRegistration) + { + _isEnabled = false; + } + + return showUserRegistration; + } + set + { + _isEnabled = value; + } + } + + public static void UseAdministratorRegistrationPage(this IAppBuilder app, Func isLocalRequest) + { + _isLocalRequest = isLocalRequest; + _isAnyUserRegistered = new Lazy(IsAnyUserRegistered); + GlobalFilters.Filters.Add(new RegistrationActionFilterAttribute()); + if (isLocalRequest()) + { + AddRoute(); + } + } + + private static bool IsAnyUserRegistered() + { + var provider = ServiceLocator.Current.GetInstance(); + int totalUsers = 0; + var res = provider.GetAllUsers(0, 1, out totalUsers); + return totalUsers > 0; + } + + public class RegistrationActionFilterAttribute : ActionFilterAttribute + { + public override void OnActionExecuting(ActionExecutingContext context) + { + var registerUrl = VirtualPathUtility.ToAbsolute("~/Register"); + if (IsEnabled && !context.RequestContext.HttpContext.Request.Path.StartsWith(registerUrl)) + { + context.Result = new RedirectResult(registerUrl); + } + } + } + + static void AddRoute() + { + var routeData = new RouteValueDictionary(); + routeData.Add("Controller", "Register"); + routeData.Add("action", "Index"); + routeData.Add("id", " UrlParameter.Optional"); + RouteTable.Routes.Add("Register", new Route("{controller}/{action}/{id}", routeData, new MvcRouteHandler()) { RouteExistingFiles = false }); + } + } +} diff --git a/src/alloy/Business/Channels/DisplayResolutionBase.cs b/src/alloy/Business/Channels/DisplayResolutionBase.cs new file mode 100644 index 0000000..996be89 --- /dev/null +++ b/src/alloy/Business/Channels/DisplayResolutionBase.cs @@ -0,0 +1,54 @@ +using EPiServer.Framework.Localization; +using EPiServer.ServiceLocation; +using EPiServer.Web; + +namespace AlloyTemplates.Business.Channels +{ + /// + /// Base class for all resolution definitions + /// + public abstract class DisplayResolutionBase : IDisplayResolution + { + private Injected LocalizationService { get; set; } + + protected DisplayResolutionBase(string name, int width, int height) + { + Id = GetType().FullName; + Name = Translate(name); + Width = width; + Height = height; + } + + /// + /// Gets the unique ID for this resolution + /// + public string Id { get; protected set; } + + /// + /// Gets the name of resolution + /// + public string Name { get; protected set; } + + /// + /// Gets the resolution width in pixels + /// + public int Width { get; protected set; } + + /// + /// Gets the resolution height in pixels + /// + public int Height { get; protected set; } + + private string Translate(string resurceKey) + { + string value; + + if(!LocalizationService.Service.TryGetString(resurceKey, out value)) + { + value = resurceKey; + } + + return value; + } + } +} diff --git a/src/alloy/Business/Channels/DisplayResolutions.cs b/src/alloy/Business/Channels/DisplayResolutions.cs new file mode 100644 index 0000000..29c2f12 --- /dev/null +++ b/src/alloy/Business/Channels/DisplayResolutions.cs @@ -0,0 +1,42 @@ +namespace AlloyTemplates.Business.Channels +{ + /// + /// Defines resolution for desktop displays + /// + public class StandardResolution : DisplayResolutionBase + { + public StandardResolution() : base("/resolutions/standard", 1366, 768) + { + } + } + + /// + /// Defines resolution for a horizontal iPad + /// + public class IpadHorizontalResolution : DisplayResolutionBase + { + public IpadHorizontalResolution() : base("/resolutions/ipadhorizontal", 1024, 768) + { + } + } + + /// + /// Defines resolution for a vertical iPhone 5s + /// + public class IphoneVerticalResolution : DisplayResolutionBase + { + public IphoneVerticalResolution() : base("/resolutions/iphonevertical", 320, 568) + { + } + } + + /// + /// Defines resolution for a vertical Android handheld device + /// + public class AndroidVerticalResolution : DisplayResolutionBase + { + public AndroidVerticalResolution() : base("/resolutions/androidvertical", 480, 800) + { + } + } +} diff --git a/src/alloy/Business/Channels/MobileChannel.cs b/src/alloy/Business/Channels/MobileChannel.cs new file mode 100644 index 0000000..79b1879 --- /dev/null +++ b/src/alloy/Business/Channels/MobileChannel.cs @@ -0,0 +1,35 @@ +using System.Web; +using System.Web.WebPages; +using EPiServer.Web; + +namespace AlloyTemplates.Business.Channels +{ + // + //Defines the 'Mobile' content channel + // + public class MobileChannel : DisplayChannel + { + public const string Name = "mobile"; + + public override string ChannelName + { + get + { + return Name; + } + } + + public override string ResolutionId + { + get + { + return typeof(IphoneVerticalResolution).FullName; + } + } + + public override bool IsActive(HttpContextBase context) + { + return context.GetOverriddenBrowser().IsMobileDevice; + } + } +} diff --git a/src/alloy/Business/Channels/WebChannel.cs b/src/alloy/Business/Channels/WebChannel.cs new file mode 100644 index 0000000..2237f35 --- /dev/null +++ b/src/alloy/Business/Channels/WebChannel.cs @@ -0,0 +1,24 @@ +using System.Web; +using EPiServer.Web; + +namespace AlloyTemplates.Business.Channels +{ + /// + /// Defines the 'Web' content channel + /// + public class WebChannel : DisplayChannel + { + public override string ChannelName + { + get + { + return "web"; + } + } + + public override bool IsActive(HttpContextBase context) + { + return !context.Request.Browser.IsMobileDevice; + } + } +} diff --git a/src/alloy/Business/ContentExtensions.cs b/src/alloy/Business/ContentExtensions.cs new file mode 100644 index 0000000..4784bc4 --- /dev/null +++ b/src/alloy/Business/ContentExtensions.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Linq; +using EPiServer.Core; +using EPiServer.Filters; +using EPiServer.Framework.Web; +using EPiServer.ServiceLocation; +using EPiServer; + +namespace AlloyTemplates.Business +{ + /// + /// Extension methods for content + /// + public static class ContentExtensions + { + /// + /// Filters content which should not be visible to the user. + /// + public static IEnumerable FilterForDisplay(this IEnumerable contents, bool requirePageTemplate = false, bool requireVisibleInMenu = false) + where T : IContent + { + var accessFilter = new FilterAccess(); + var publishedFilter = new FilterPublished(); + contents = contents.Where(x => !publishedFilter.ShouldFilter(x) && !accessFilter.ShouldFilter(x)); + if (requirePageTemplate) + { + var templateFilter = ServiceLocator.Current.GetInstance(); + templateFilter.TemplateTypeCategories = TemplateTypeCategories.Page; + contents = contents.Where(x => !templateFilter.ShouldFilter(x)); + } + if (requireVisibleInMenu) + { + contents = contents.Where(x => VisibleInMenu(x)); + } + return contents; + } + + private static bool VisibleInMenu(IContent content) + { + var page = content as PageData; + if (page == null) + { + return true; + } + return page.VisibleInMenu; + } + } +} diff --git a/src/alloy/Business/ContentLocator.cs b/src/alloy/Business/ContentLocator.cs new file mode 100644 index 0000000..2eed3a9 --- /dev/null +++ b/src/alloy/Business/ContentLocator.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using AlloyTemplates.Models.Pages; +using EPiServer; +using EPiServer.Core; +using EPiServer.Filters; +using EPiServer.Shell.Configuration; +using EPiServer.Web; + +namespace AlloyTemplates.Business +{ + public class ContentLocator + { + private readonly IContentLoader _contentLoader; + private readonly IContentProviderManager _providerManager; + private readonly IPageCriteriaQueryService _pageCriteriaQueryService; + + public ContentLocator(IContentLoader contentLoader, IContentProviderManager providerManager, IPageCriteriaQueryService pageCriteriaQueryService) + { + _contentLoader = contentLoader; + _providerManager = providerManager; + _pageCriteriaQueryService = pageCriteriaQueryService; + } + + public virtual IEnumerable GetAll(ContentReference rootLink) + where T : PageData + { + var children = _contentLoader.GetChildren(rootLink); + foreach (var child in children) + { + var childOfRequestedTyped = child as T; + if (childOfRequestedTyped != null) + { + yield return childOfRequestedTyped; + } + foreach (var descendant in GetAll(child.ContentLink)) + { + yield return descendant; + } + } + } + + /// + /// Returns pages of a specific page type + /// + /// + /// + /// ID of the page type to filter by + /// + public IEnumerable FindPagesByPageType(PageReference pageLink, bool recursive, int pageTypeId) + { + if (ContentReference.IsNullOrEmpty(pageLink)) + { + throw new ArgumentNullException("pageLink", "No page link specified, unable to find pages"); + } + + var pages = recursive + ? FindPagesByPageTypeRecursively(pageLink, pageTypeId) + : _contentLoader.GetChildren(pageLink); + + return pages; + } + + // Type specified through page type ID + private IEnumerable FindPagesByPageTypeRecursively(PageReference pageLink, int pageTypeId) + { + var criteria = new PropertyCriteriaCollection + { + new PropertyCriteria + { + Name = "PageTypeID", + Type = PropertyDataType.PageType, + Condition = CompareCondition.Equal, + Value = pageTypeId.ToString(CultureInfo.InvariantCulture) + } + }; + + // Include content providers serving content beneath the page link specified for the search + if (_providerManager.ProviderMap.CustomProvidersExist) + { + var contentProvider = _providerManager.ProviderMap.GetProvider(pageLink); + + if (contentProvider.HasCapability(ContentProviderCapabilities.Search)) + { + criteria.Add(new PropertyCriteria + { + Name = "EPI:MultipleSearch", + Value = contentProvider.ProviderKey + }); + } + } + + return _pageCriteriaQueryService.FindPagesWithCriteria(pageLink, criteria); + } + + /// + /// Returns all contact pages beneath the main contacts container + /// + /// + public IEnumerable GetContactPages() + { + var contactsRootPageLink = _contentLoader.Get(SiteDefinition.Current.StartPage).ContactsPageLink; + + if (ContentReference.IsNullOrEmpty(contactsRootPageLink)) + { + throw new MissingConfigurationException("No contact page root specified in site settings, unable to retrieve contact pages"); + } + + return _contentLoader.GetChildren(contactsRootPageLink).OrderBy(p => p.PageName); + } + } +} diff --git a/src/alloy/Business/EditorDescriptors/ContactPageSelectionFactory.cs b/src/alloy/Business/EditorDescriptors/ContactPageSelectionFactory.cs new file mode 100644 index 0000000..0313777 --- /dev/null +++ b/src/alloy/Business/EditorDescriptors/ContactPageSelectionFactory.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Linq; +using EPiServer.ServiceLocation; +using EPiServer.Shell.ObjectEditing; + +namespace AlloyTemplates.Business.EditorDescriptors +{ + /// + /// Provides a list of options corresponding to ContactPage pages on the site + /// + /// + public class ContactPageSelectionFactory : ISelectionFactory + { + private Injected ContentLocator { get; set; } + + public IEnumerable GetSelections(ExtendedMetadata metadata) + { + var contactPages = ContentLocator.Service.GetContactPages(); + + return new List(contactPages.Select(c => new SelectItem {Value = c.PageLink, Text = c.Name})); + } + } +} diff --git a/src/alloy/Business/EditorDescriptors/ContactPageSelector.cs b/src/alloy/Business/EditorDescriptors/ContactPageSelector.cs new file mode 100644 index 0000000..f257576 --- /dev/null +++ b/src/alloy/Business/EditorDescriptors/ContactPageSelector.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using EPiServer.Core; +using EPiServer.Shell.ObjectEditing; +using EPiServer.Shell.ObjectEditing.EditorDescriptors; + +namespace AlloyTemplates.Business.EditorDescriptors +{ + /// + /// Registers an editor to select a ContactPage for a PageReference property using a dropdown + /// + [EditorDescriptorRegistration(TargetType = typeof(PageReference), UIHint = Global.SiteUIHints.Contact)] + public class ContactPageSelector : EditorDescriptor + { + public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable attributes) + { + SelectionFactoryType = typeof(ContactPageSelectionFactory); + + ClientEditingClass = "epi-cms/contentediting/editors/SelectionEditor"; + + base.ModifyMetadata(metadata, attributes); + } + } +} diff --git a/src/alloy/Business/EditorDescriptors/StringListEditorDescriptor.cs b/src/alloy/Business/EditorDescriptors/StringListEditorDescriptor.cs new file mode 100644 index 0000000..6002a6a --- /dev/null +++ b/src/alloy/Business/EditorDescriptors/StringListEditorDescriptor.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using EPiServer.Shell.ObjectEditing.EditorDescriptors; +using EPiServer.Shell.ObjectEditing; + +namespace AlloyTemplates.Business.EditorDescriptors +{ + /// + /// Register an editor for StringList properties + /// + [EditorDescriptorRegistration(TargetType = typeof(String[]), UIHint = Global.SiteUIHints.Strings)] + public class StringListEditorDescriptor : EditorDescriptor + { + public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable attributes) + { + ClientEditingClass = "alloy/editors/StringList"; + + base.ModifyMetadata(metadata, attributes); + } + } +} diff --git a/src/alloy/Business/IModifyLayout.cs b/src/alloy/Business/IModifyLayout.cs new file mode 100644 index 0000000..9db6d36 --- /dev/null +++ b/src/alloy/Business/IModifyLayout.cs @@ -0,0 +1,13 @@ +using AlloyTemplates.Models.ViewModels; + +namespace AlloyTemplates.Business +{ + /// + /// Defines a method which may be invoked by PageContextActionFilter allowing controllers + /// to modify common layout properties of the view model. + /// + interface IModifyLayout + { + void ModifyLayout(LayoutModel layoutModel); + } +} diff --git a/src/alloy/Business/Initialization/BundleConfig.cs b/src/alloy/Business/Initialization/BundleConfig.cs new file mode 100644 index 0000000..57dd961 --- /dev/null +++ b/src/alloy/Business/Initialization/BundleConfig.cs @@ -0,0 +1,41 @@ +using System.Web.Optimization; +using EPiServer.Framework; +using EPiServer.Framework.Initialization; + +namespace AlloyTemplates.Business.Initialization +{ + [InitializableModule] + public class BundleConfig : IInitializableModule + { + public void Initialize(InitializationEngine context) + { + if (context.HostType == HostType.WebApplication) + { + RegisterBundles(BundleTable.Bundles); + } + } + + // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725 + public static void RegisterBundles(BundleCollection bundles) + { + bundles.Add(new ScriptBundle("~/bundles/js").Include( + "~/Static/js/jquery.js", //jquery.js can be removed and linked from CDN instead, we use a local one for demo purposes without internet connectionzz + "~/Static/js/bootstrap.js")); + + bundles.Add(new StyleBundle("~/bundles/css") + .Include("~/Static/css/bootstrap.css", new CssRewriteUrlTransform()) + .Include("~/Static/css/bootstrap-responsive.css") + .Include("~/Static/css/media.css") + .Include("~/Static/css/style.css", new CssRewriteUrlTransform()) + .Include("~/Static/css/editmode.css")); + } + + public void Uninitialize(InitializationEngine context) + { + } + + public void Preload(string[] parameters) + { + } + } +} diff --git a/src/alloy/Business/Initialization/CustomizedRenderingInitialization.cs b/src/alloy/Business/Initialization/CustomizedRenderingInitialization.cs new file mode 100644 index 0000000..515625e --- /dev/null +++ b/src/alloy/Business/Initialization/CustomizedRenderingInitialization.cs @@ -0,0 +1,36 @@ +using System.Web.Mvc; +using EPiServer.Framework; +using EPiServer.Framework.Initialization; +using EPiServer.ServiceLocation; +using AlloyTemplates.Business.Rendering; +using EPiServer.Web; + +namespace AlloyTemplates.Business.Initialization +{ + /// + /// Module for customizing templates and rendering. + /// + [ModuleDependency(typeof(EPiServer.Web.InitializationModule))] + public class CustomizedRenderingInitialization : IInitializableModule + { + public void Initialize(InitializationEngine context) + { + //Add custom view engine allowing partials to be placed in additional locations + //Note that we add it first in the list to optimize view resolving when using DisplayFor/PropertyFor + ViewEngines.Engines.Insert(0, new SiteViewEngine()); + + context.Locate.TemplateResolver() + .TemplateResolved += TemplateCoordinator.OnTemplateResolved; + } + + public void Uninitialize(InitializationEngine context) + { + ServiceLocator.Current.GetInstance() + .TemplateResolved -= TemplateCoordinator.OnTemplateResolved; + } + + public void Preload(string[] parameters) + { + } + } +} diff --git a/src/alloy/Business/Initialization/DependencyResolverInitialization.cs b/src/alloy/Business/Initialization/DependencyResolverInitialization.cs new file mode 100644 index 0000000..604702e --- /dev/null +++ b/src/alloy/Business/Initialization/DependencyResolverInitialization.cs @@ -0,0 +1,39 @@ +using System.Web.Mvc; +using EPiServer.Framework; +using EPiServer.Framework.Initialization; +using EPiServer.ServiceLocation; +using AlloyTemplates.Business.Rendering; +using EPiServer.Web.Mvc; +using EPiServer.Web.Mvc.Html; + +namespace AlloyTemplates.Business.Initialization +{ + [InitializableModule] + public class DependencyResolverInitialization : IConfigurableModule + { + public void ConfigureContainer(ServiceConfigurationContext context) + { + //Implementations for custom interfaces can be registered here. + + context.ConfigurationComplete += (o, e) => + { + //Register custom implementations that should be used in favour of the default implementations + context.Services.AddTransient() + .AddTransient(); + }; + } + + public void Initialize(InitializationEngine context) + { + DependencyResolver.SetResolver(new ServiceLocatorDependencyResolver(context.Locate.Advanced)); + } + + public void Uninitialize(InitializationEngine context) + { + } + + public void Preload(string[] parameters) + { + } + } +} diff --git a/src/alloy/Business/Initialization/DisplayModesInitialization.cs b/src/alloy/Business/Initialization/DisplayModesInitialization.cs new file mode 100644 index 0000000..c8a01d9 --- /dev/null +++ b/src/alloy/Business/Initialization/DisplayModesInitialization.cs @@ -0,0 +1,49 @@ +using System.Linq; +using System.Web; +using System.Web.WebPages; +using EPiServer.Framework; +using EPiServer.Framework.Initialization; +using EPiServer.ServiceLocation; +using AlloyTemplates.Business.Channels; +using EPiServer.Web; + +namespace AlloyTemplates.Business.Initialization +{ + /// + /// Adds a new display mode for mobile which is active if the mobile channel is active in addition to if the request is from a mobile device (like the default one) + /// + /// + /// It's also possible to map a display mode as a channel through the DisplayChannelService.RegisterDisplayMode() method. + /// Adding channels that way does not however enable specifying ResolutionId which we want to do for the mobile channel. + /// + [ModuleDependency(typeof(EPiServer.Web.InitializationModule))] + public class DisplayModesInitialization : IInitializableModule + { + public void Initialize(InitializationEngine context) + { + var mobileChannelDisplayMode = new DefaultDisplayMode("mobile") + { + ContextCondition = IsMobileDisplayModeActive + }; + DisplayModeProvider.Instance.Modes.Insert(0, mobileChannelDisplayMode); + } + + private static bool IsMobileDisplayModeActive(HttpContextBase httpContext) + { + if (httpContext.GetOverriddenBrowser().IsMobileDevice) + { + return true; + } + var displayChannelService = ServiceLocator.Current.GetInstance(); + return displayChannelService.GetActiveChannels(httpContext).Any(x => x.ChannelName == MobileChannel.Name); + } + + public void Uninitialize(InitializationEngine context) + { + } + + public void Preload(string[] parameters) + { + } + } +} diff --git a/src/alloy/Business/Initialization/DisplayRegistryInitialization.cs b/src/alloy/Business/Initialization/DisplayRegistryInitialization.cs new file mode 100644 index 0000000..4aec591 --- /dev/null +++ b/src/alloy/Business/Initialization/DisplayRegistryInitialization.cs @@ -0,0 +1,34 @@ +using EPiServer.Framework; +using EPiServer.Framework.Initialization; +using EPiServer.ServiceLocation; +using EPiServer.Web; +using System.Collections.Generic; +using System.Web.Mvc; + +namespace AlloyTemplates.Business.Initialization +{ + [InitializableModule] + [ModuleDependency(typeof(EPiServer.Web.InitializationModule))] + public class DisplayRegistryInitialization : IInitializableModule + { + public void Initialize(InitializationEngine context) + { + if (context.HostType == HostType.WebApplication) + { + // Register Display Options + var options = ServiceLocator.Current.GetInstance(); + options + .Add("full", "/displayoptions/full", Global.ContentAreaTags.FullWidth, "", "epi-icon__layout--full") + .Add("wide", "/displayoptions/wide", Global.ContentAreaTags.TwoThirdsWidth, "", "epi-icon__layout--two-thirds") + .Add("narrow", "/displayoptions/narrow", Global.ContentAreaTags.OneThirdWidth, "", "epi-icon__layout--one-third"); + + AreaRegistration.RegisterAllAreas(); + + } + } + + public void Preload(string[] parameters){} + + public void Uninitialize(InitializationEngine context){} + } +} diff --git a/src/alloy/Business/Initialization/ExtendedTinyMceInitialization.cs b/src/alloy/Business/Initialization/ExtendedTinyMceInitialization.cs new file mode 100644 index 0000000..771d87c --- /dev/null +++ b/src/alloy/Business/Initialization/ExtendedTinyMceInitialization.cs @@ -0,0 +1,43 @@ +using AlloyTemplates.Models.Blocks; +using AlloyTemplates.Models.Pages; +using EPiServer.Cms.TinyMce.Core; +using EPiServer.Framework; +using EPiServer.Framework.Initialization; +using EPiServer.ServiceLocation; + +namespace AlloyTemplates.Business.Initialization +{ + [ModuleDependency(typeof(TinyMceInitialization))] + public class ExtendedTinyMceInitialization : IConfigurableModule + { + public void Initialize(InitializationEngine context) + { + } + + public void Uninitialize(InitializationEngine context) + { + } + + public void ConfigureContainer(ServiceConfigurationContext context) + { + context.Services.Configure(config => + { + // Add content CSS to the default settings. + config.Default() + .ContentCss("/static/css/editor.css"); + + // This will clone the default settings object and extend it by + // limiting the block formats for the MainBody property of an ArticlePage. + config.For(t => t.MainBody) + .BlockFormats("Paragraph=p;Header 1=h1;Header 2=h2;Header 3=h3"); + + // Passing a second argument to For<> will clone the given settings object + // instead of the default one and extend it with some basic toolbar commands. + config.For(t => t.MainBody, config.Empty()) + .AddEpiserverSupport() + .DisableMenubar() + .Toolbar("bold italic underline strikethrough"); + }); + } + } +} diff --git a/src/alloy/Business/Initialization/FilterConfig.cs b/src/alloy/Business/Initialization/FilterConfig.cs new file mode 100644 index 0000000..880fd92 --- /dev/null +++ b/src/alloy/Business/Initialization/FilterConfig.cs @@ -0,0 +1,27 @@ +using System.Web.Mvc; +using EPiServer.Framework; +using EPiServer.Framework.Initialization; +using EPiServer.ServiceLocation; + +namespace AlloyTemplates.Business.Initialization +{ + /// + /// Module for registering filters which will be applied to controller actions. + /// + [ModuleDependency(typeof(EPiServer.Web.InitializationModule))] + public class FilterConfig : IInitializableModule + { + public void Initialize(InitializationEngine context) + { + GlobalFilters.Filters.Add(ServiceLocator.Current.GetInstance()); + } + + public void Uninitialize(InitializationEngine context) + { + } + + public void Preload(string[] parameters) + { + } + } +} diff --git a/src/alloy/Business/PageContextActionFilter.cs b/src/alloy/Business/PageContextActionFilter.cs new file mode 100644 index 0000000..44dbba4 --- /dev/null +++ b/src/alloy/Business/PageContextActionFilter.cs @@ -0,0 +1,55 @@ +using System.Web.Mvc; +using AlloyTemplates.Models.Pages; +using AlloyTemplates.Models.ViewModels; +using EPiServer.Web.Routing; + +namespace AlloyTemplates.Business +{ + /// + /// Intercepts actions with view models of type IPageViewModel and populates the view models + /// Layout and Section properties. + /// + /// + /// This filter frees controllers for pages from having to care about common context needed by layouts + /// and other page framework components allowing the controllers to focus on the specifics for the page types + /// and actions that they handle. + /// + public class PageContextActionFilter : IResultFilter + { + private readonly PageViewContextFactory _contextFactory; + public PageContextActionFilter(PageViewContextFactory contextFactory) + { + _contextFactory = contextFactory; + } + + public void OnResultExecuting(ResultExecutingContext filterContext) + { + var viewModel = filterContext.Controller.ViewData.Model; + + var model = viewModel as IPageViewModel; + if (model != null) + { + var currentContentLink = filterContext.RequestContext.GetContentLink(); + + var layoutModel = model.Layout ?? _contextFactory.CreateLayoutModel(currentContentLink, filterContext.RequestContext); + + var layoutController = filterContext.Controller as IModifyLayout; + if(layoutController != null) + { + layoutController.ModifyLayout(layoutModel); + } + + model.Layout = layoutModel; + + if (model.Section == null) + { + model.Section = _contextFactory.GetSection(currentContentLink); + } + } + } + + public void OnResultExecuted(ResultExecutedContext filterContext) + { + } + } +} diff --git a/src/alloy/Business/PageTypeExtensions.cs b/src/alloy/Business/PageTypeExtensions.cs new file mode 100644 index 0000000..a528683 --- /dev/null +++ b/src/alloy/Business/PageTypeExtensions.cs @@ -0,0 +1,24 @@ +using System; +using EPiServer.DataAbstraction; +using EPiServer.ServiceLocation; + +namespace AlloyTemplates.Business +{ + /// + /// Provides extension methods for types intended to be used when working with page types + /// + public static class PageTypeExtensions + { + /// + /// Returns the definition for a specific page type + /// + /// + /// + public static PageType GetPageType(this Type pageType) + { + var pageTypeRepository = ServiceLocator.Current.GetInstance>(); + + return pageTypeRepository.Load(pageType); + } + } +} diff --git a/src/alloy/Business/PageViewContextFactory.cs b/src/alloy/Business/PageViewContextFactory.cs new file mode 100644 index 0000000..93f4725 --- /dev/null +++ b/src/alloy/Business/PageViewContextFactory.cs @@ -0,0 +1,79 @@ +using System.Linq; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; +using System.Web.Security; +using AlloyTemplates.Models.Pages; +using AlloyTemplates.Models.ViewModels; +using EPiServer; +using EPiServer.Core; +using EPiServer.Data; +using EPiServer.Web; +using EPiServer.Web.Routing; + +namespace AlloyTemplates.Business +{ + public class PageViewContextFactory + { + private readonly IContentLoader _contentLoader; + private readonly UrlResolver _urlResolver; + private readonly IDatabaseMode _databaseMode; + + public PageViewContextFactory(IContentLoader contentLoader, UrlResolver urlResolver, IDatabaseMode databaseMode) + { + _contentLoader = contentLoader; + _urlResolver = urlResolver; + _databaseMode = databaseMode; + } + + public virtual LayoutModel CreateLayoutModel(ContentReference currentContentLink, RequestContext requestContext) + { + var startPageContentLink = SiteDefinition.Current.StartPage; + + // Use the content link with version information when editing the startpage, + // otherwise the published version will be used when rendering the props below. + if (currentContentLink.CompareToIgnoreWorkID(startPageContentLink)) + { + startPageContentLink = currentContentLink; + } + + var startPage = _contentLoader.Get(startPageContentLink); + + return new LayoutModel + { + Logotype = startPage.SiteLogotype, + LogotypeLinkUrl = new MvcHtmlString(_urlResolver.GetUrl(SiteDefinition.Current.StartPage)), + ProductPages = startPage.ProductPageLinks, + CompanyInformationPages = startPage.CompanyInformationPageLinks, + NewsPages = startPage.NewsPageLinks, + CustomerZonePages = startPage.CustomerZonePageLinks, + LoggedIn = requestContext.HttpContext.User.Identity.IsAuthenticated, + LoginUrl = new MvcHtmlString(GetLoginUrl(currentContentLink)), + SearchActionUrl = new MvcHtmlString(EPiServer.Web.Routing.UrlResolver.Current.GetUrl(startPage.SearchPageLink)), + IsInReadonlyMode = _databaseMode.DatabaseMode == DatabaseMode.ReadOnly + }; + } + + private string GetLoginUrl(ContentReference returnToContentLink) + { + return string.Format( + "{0}?ReturnUrl={1}", + (FormsAuthentication.IsEnabled ? FormsAuthentication.LoginUrl : VirtualPathUtility.ToAbsolute(Global.AppRelativeLoginPath)), + _urlResolver.GetUrl(returnToContentLink)); + } + + public virtual IContent GetSection(ContentReference contentLink) + { + var currentContent = _contentLoader.Get(contentLink); + if (currentContent.ParentLink != null && currentContent.ParentLink.CompareToIgnoreWorkID(SiteDefinition.Current.StartPage)) + { + return currentContent; + } + + return _contentLoader.GetAncestors(contentLink) + .OfType() + .SkipWhile(x => x.ParentLink == null || !x.ParentLink.CompareToIgnoreWorkID(SiteDefinition.Current.StartPage)) + .FirstOrDefault(); + } + } +} diff --git a/src/alloy/Business/Rendering/AlloyContentAreaRenderer.cs b/src/alloy/Business/Rendering/AlloyContentAreaRenderer.cs new file mode 100644 index 0000000..404e14e --- /dev/null +++ b/src/alloy/Business/Rendering/AlloyContentAreaRenderer.cs @@ -0,0 +1,62 @@ +using System; +using System.Web.Mvc; +using EPiServer.Core; +using EPiServer.Core.Html.StringParsing; +using EPiServer.Web; +using EPiServer.Web.Mvc; +using EPiServer.Web.Mvc.Html; +using EPiServer; + +namespace AlloyTemplates.Business.Rendering +{ + /// + /// Extends the default to apply custom CSS classes to each . + /// + public class AlloyContentAreaRenderer : ContentAreaRenderer + { + protected override string GetContentAreaItemCssClass(HtmlHelper htmlHelper, ContentAreaItem contentAreaItem) + { + var baseItemClass = base.GetContentAreaItemCssClass(htmlHelper, contentAreaItem); + + var tag = GetContentAreaItemTemplateTag(htmlHelper, contentAreaItem); + return $"block {baseItemClass} {GetTypeSpecificCssClasses(contentAreaItem, ContentRepository)} {GetCssClassForTag(tag)} {tag}"; + } + + /// + /// Gets a CSS class used for styling based on a tag name (ie a Bootstrap class name) + /// + /// Any tag name available, see + private static string GetCssClassForTag(string tagName) + { + if (string.IsNullOrEmpty(tagName)) + { + return ""; + } + switch (tagName.ToLower()) + { + case "span12": + return "full"; + case "span8": + return "wide"; + case "span6": + return "half"; + default: + return string.Empty; + } + } + + private static string GetTypeSpecificCssClasses(ContentAreaItem contentAreaItem, IContentRepository contentRepository) + { + var content = contentAreaItem.GetContent(); + var cssClass = content == null ? String.Empty : content.GetOriginalType().Name.ToLowerInvariant(); + + var customClassContent = content as ICustomCssInContentArea; + if (customClassContent != null && !string.IsNullOrWhiteSpace(customClassContent.ContentAreaCssClass)) + { + cssClass += string.Format(" {0}", customClassContent.ContentAreaCssClass); + } + + return cssClass; + } + } +} diff --git a/src/alloy/Business/Rendering/ErrorHandlingContentRenderer.cs b/src/alloy/Business/Rendering/ErrorHandlingContentRenderer.cs new file mode 100644 index 0000000..06409b9 --- /dev/null +++ b/src/alloy/Business/Rendering/ErrorHandlingContentRenderer.cs @@ -0,0 +1,106 @@ +using System; +using System.IO; +using System.Web; +using System.Web.Mvc; +using System.Web.Mvc.Html; +using EPiServer.Core; +using EPiServer.DataAbstraction; +using EPiServer.Security; +using AlloyTemplates.Models.ViewModels; +using EPiServer.Web.Mvc; + +namespace AlloyTemplates.Business.Rendering +{ + /// + /// Wraps an MvcContentRenderer and adds error handling to ensure that blocks and other content + /// rendered as parts of pages won't crash the entire page if a non-critical exception occurs while rendering it. + /// + /// + /// Prints an error message for editors so that they can easily report errors to developers. + /// + public class ErrorHandlingContentRenderer : IContentRenderer + { + private readonly MvcContentRenderer _mvcRenderer; + public ErrorHandlingContentRenderer(MvcContentRenderer mvcRenderer) + { + _mvcRenderer = mvcRenderer; + } + + /// + /// Renders the contentData using the wrapped renderer and catches common, non-critical exceptions. + /// + public void Render(HtmlHelper helper, PartialRequest partialRequestHandler, IContentData contentData, TemplateModel templateModel) + { + try + { + _mvcRenderer.Render(helper, partialRequestHandler, contentData, templateModel); + } + catch (NullReferenceException ex) + { + if (HttpContext.Current.IsDebuggingEnabled) + { + //If debug="true" we assume a developer is making the request + throw; + } + HandlerError(helper, contentData, ex); + } + catch (ArgumentException ex) + { + if (HttpContext.Current.IsDebuggingEnabled) + { + throw; + } + HandlerError(helper, contentData, ex); + } + catch (ApplicationException ex) + { + if (HttpContext.Current.IsDebuggingEnabled) + { + throw; + } + HandlerError(helper, contentData, ex); + } + catch (InvalidOperationException ex) + { + if (HttpContext.Current.IsDebuggingEnabled) + { + throw; + } + HandlerError(helper, contentData, ex); + } + catch (NotImplementedException ex) + { + if (HttpContext.Current.IsDebuggingEnabled) + { + throw; + } + HandlerError(helper, contentData, ex); + } + catch (IOException ex) + { + if (HttpContext.Current.IsDebuggingEnabled) + { + throw; + } + HandlerError(helper, contentData, ex); + } + catch (EPiServerException ex) + { + if (HttpContext.Current.IsDebuggingEnabled) + { + throw; + } + HandlerError(helper, contentData, ex); + } + } + + private void HandlerError(HtmlHelper helper, IContentData contentData, Exception renderingException) + { + if (PrincipalInfo.HasEditAccess) + { + var errorModel = new ContentRenderingErrorModel(contentData, renderingException); + helper.RenderPartial("TemplateError", errorModel); + } + } + } +} diff --git a/src/alloy/Business/Rendering/IContainerPage.cs b/src/alloy/Business/Rendering/IContainerPage.cs new file mode 100644 index 0000000..7aee406 --- /dev/null +++ b/src/alloy/Business/Rendering/IContainerPage.cs @@ -0,0 +1,9 @@ +namespace AlloyTemplates.Business.Rendering +{ + /// + /// Marker interface for content types which should not be handled by DefaultPageController. + /// + interface IContainerPage + { + } +} diff --git a/src/alloy/Business/Rendering/ICustomCssInContentArea.cs b/src/alloy/Business/Rendering/ICustomCssInContentArea.cs new file mode 100644 index 0000000..5878368 --- /dev/null +++ b/src/alloy/Business/Rendering/ICustomCssInContentArea.cs @@ -0,0 +1,11 @@ +namespace AlloyTemplates.Business.Rendering +{ + /// + /// Defines a property for CSS class(es) which will be added to the class + /// attribute of containing elements when rendered in a content area with a size tag. + /// + interface ICustomCssInContentArea + { + string ContentAreaCssClass { get; } + } +} diff --git a/src/alloy/Business/Rendering/SiteViewEngine.cs b/src/alloy/Business/Rendering/SiteViewEngine.cs new file mode 100644 index 0000000..e7fa1a3 --- /dev/null +++ b/src/alloy/Business/Rendering/SiteViewEngine.cs @@ -0,0 +1,23 @@ +using System.Linq; +using System.Web.Mvc; + +namespace AlloyTemplates.Business.Rendering +{ + /// + /// Extends the Razor view engine to include the folders ~/Views/Shared/Blocks/ and ~/Views/Shared/PagePartials/ + /// when looking for partial views. + /// + public class SiteViewEngine : RazorViewEngine + { + private static readonly string[] AdditionalPartialViewFormats = new[] + { + TemplateCoordinator.BlockFolder + "{0}.cshtml", + TemplateCoordinator.PagePartialsFolder + "{0}.cshtml" + }; + + public SiteViewEngine() + { + PartialViewLocationFormats = PartialViewLocationFormats.Union(AdditionalPartialViewFormats).ToArray(); + } + } +} diff --git a/src/alloy/Business/Rendering/TemplateCoordinator.cs b/src/alloy/Business/Rendering/TemplateCoordinator.cs new file mode 100644 index 0000000..6c69177 --- /dev/null +++ b/src/alloy/Business/Rendering/TemplateCoordinator.cs @@ -0,0 +1,100 @@ +using EPiServer.Core; +using EPiServer.DataAbstraction; +using EPiServer.ServiceLocation; +using AlloyTemplates.Controllers; +using AlloyTemplates.Models.Blocks; +using AlloyTemplates.Models.Pages; +using EPiServer.Web; +using EPiServer.Web.Mvc; + +namespace AlloyTemplates.Business.Rendering +{ + [ServiceConfiguration(typeof(IViewTemplateModelRegistrator))] + public class TemplateCoordinator : IViewTemplateModelRegistrator + { + public const string BlockFolder = "~/Views/Shared/Blocks/"; + public const string PagePartialsFolder = "~/Views/Shared/PagePartials/"; + + public static void OnTemplateResolved(object sender, TemplateResolverEventArgs args) + { + //Disable DefaultPageController for page types that shouldn't have any renderer as pages + if (args.ItemToRender is IContainerPage && args.SelectedTemplate != null && args.SelectedTemplate.TemplateType == typeof(DefaultPageController)) + { + args.SelectedTemplate = null; + } + } + + /// + /// Registers renderers/templates which are not automatically discovered, + /// i.e. partial views whose names does not match a content type's name. + /// + /// + /// Using only partial views instead of controllers for blocks and page partials + /// has performance benefits as they will only require calls to RenderPartial instead of + /// RenderAction for controllers. + /// Registering partial views as templates this way also enables specifying tags and + /// that a template supports all types inheriting from the content type/model type. + /// + public void Register(TemplateModelCollection viewTemplateModelRegistrator) + { + viewTemplateModelRegistrator.Add(typeof(JumbotronBlock), new TemplateModel + { + Tags = new[] { Global.ContentAreaTags.FullWidth }, + AvailableWithoutTag = false, + Path = BlockPath("JumbotronBlockWide.cshtml") + }); + + viewTemplateModelRegistrator.Add(typeof(TeaserBlock), new TemplateModel + { + Name = "TeaserBlockWide", + Tags = new[] { Global.ContentAreaTags.TwoThirdsWidth, Global.ContentAreaTags.FullWidth }, + AvailableWithoutTag = false, + Path = BlockPath("TeaserBlockWide.cshtml") + }); + + viewTemplateModelRegistrator.Add(typeof(SitePageData), new TemplateModel + { + Name = "PagePartial", + Inherit = true, + AvailableWithoutTag = true, + Path = PagePartialPath("Page.cshtml") + }); + + viewTemplateModelRegistrator.Add(typeof(SitePageData), new TemplateModel + { + Name = "PagePartialWide", + Inherit = true, + Tags = new[] { Global.ContentAreaTags.TwoThirdsWidth, Global.ContentAreaTags.FullWidth }, + AvailableWithoutTag = false, + Path = PagePartialPath("PageWide.cshtml") + }); + + viewTemplateModelRegistrator.Add(typeof(ContactPage), new TemplateModel + { + Name = "ContactPagePartialWide", + Tags = new[] { Global.ContentAreaTags.TwoThirdsWidth, Global.ContentAreaTags.FullWidth }, + AvailableWithoutTag = false, + Path = PagePartialPath("ContactPageWide.cshtml") + }); + + viewTemplateModelRegistrator.Add(typeof(IContentData), new TemplateModel + { + Name = "NoRendererMessage", + Inherit = true, + Tags = new[] { Global.ContentAreaTags.NoRenderer }, + AvailableWithoutTag = false, + Path = BlockPath("NoRenderer.cshtml") + }); + } + + private static string BlockPath(string fileName) + { + return string.Format("{0}{1}", BlockFolder, fileName); + } + + private static string PagePartialPath(string fileName) + { + return string.Format("{0}{1}", PagePartialsFolder, fileName); + } + } +} diff --git a/src/alloy/Business/SearchService.cs b/src/alloy/Business/SearchService.cs new file mode 100644 index 0000000..44744a3 --- /dev/null +++ b/src/alloy/Business/SearchService.cs @@ -0,0 +1,74 @@ +using System.Collections.Generic; +using System.Web; +using EPiServer.Core; +using EPiServer.Search; +using EPiServer.Search.Queries; +using EPiServer.Search.Queries.Lucene; +using EPiServer.Security; +using EPiServer; +using EPiServer.ServiceLocation; + +namespace AlloyTemplates.Business +{ + public class SearchService + { + private readonly SearchHandler _searchHandler; + private readonly IContentLoader _contentLoader; + + public SearchService(SearchHandler searchHandler, IContentLoader contentLoader) + { + _searchHandler = searchHandler; + _contentLoader = contentLoader; + } + + public virtual bool IsActive + { + get { return ServiceLocator.Current.GetInstance().Active; } + } + + public virtual SearchResults Search(string searchText, IEnumerable searchRoots, HttpContextBase context, string languageBranch, int maxResults) + { + var query = CreateQuery(searchText, searchRoots, context, languageBranch); + return _searchHandler.GetSearchResults(query, 1, maxResults); + } + + private IQueryExpression CreateQuery(string searchText, IEnumerable searchRoots, HttpContextBase context, string languageBranch) + { + //Main query which groups other queries. Each query added + //must match in order for a page or file to be returned. + var query = new GroupQuery(LuceneOperator.AND); + + //Add free text query to the main query + query.QueryExpressions.Add(new FieldQuery(searchText)); + + //Search for pages using the provided language + var pageTypeQuery = new GroupQuery(LuceneOperator.AND); + pageTypeQuery.QueryExpressions.Add(new ContentQuery()); + pageTypeQuery.QueryExpressions.Add(new FieldQuery(languageBranch, Field.Culture)); + + //Search for media without languages + var contentTypeQuery = new GroupQuery(LuceneOperator.OR); + contentTypeQuery.QueryExpressions.Add(new ContentQuery()); + contentTypeQuery.QueryExpressions.Add(pageTypeQuery); + + query.QueryExpressions.Add(contentTypeQuery); + + //Create and add query which groups type conditions using OR + var typeQueries = new GroupQuery(LuceneOperator.OR); + query.QueryExpressions.Add(typeQueries); + + foreach (var root in searchRoots) + { + var contentRootQuery = new VirtualPathQuery(); + contentRootQuery.AddContentNodes(root); + typeQueries.QueryExpressions.Add(contentRootQuery); + } + + var accessRightsQuery = new AccessControlListQuery(); + accessRightsQuery.AddAclForUser(PrincipalInfo.Current, context); + query.QueryExpressions.Add(accessRightsQuery); + + return query; + } + } +} diff --git a/src/alloy/Business/ServiceLocatorDependencyResolver.cs b/src/alloy/Business/ServiceLocatorDependencyResolver.cs new file mode 100644 index 0000000..c8e76c1 --- /dev/null +++ b/src/alloy/Business/ServiceLocatorDependencyResolver.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web.Mvc; +using EPiServer.ServiceLocation; + +namespace AlloyTemplates.Business +{ + public class ServiceLocatorDependencyResolver : IDependencyResolver + { + readonly IServiceLocator _serviceLocator; + + public ServiceLocatorDependencyResolver(IServiceLocator serviceLocator) + { + _serviceLocator = serviceLocator; + } + + public object GetService(Type serviceType) + { + if (serviceType.IsInterface || serviceType.IsAbstract) + { + return GetInterfaceService(serviceType); + } + return GetConcreteService(serviceType); + } + + private object GetConcreteService(Type serviceType) + { + try + { + // Can't use TryGetInstance here because it won’t create concrete types + return _serviceLocator.GetInstance(serviceType); + } + catch (ActivationException) + { + return null; + } + } + + private object GetInterfaceService(Type serviceType) + { + object instance; + return _serviceLocator.TryGetExistingInstance(serviceType, out instance) ? instance : null; + } + + public IEnumerable GetServices(Type serviceType) + { + return _serviceLocator.GetAllInstances(serviceType).Cast(); + } + } +} diff --git a/src/alloy/Business/UIDescriptors/ContainerPageUIDescriptor.cs b/src/alloy/Business/UIDescriptors/ContainerPageUIDescriptor.cs new file mode 100644 index 0000000..ba4d40c --- /dev/null +++ b/src/alloy/Business/UIDescriptors/ContainerPageUIDescriptor.cs @@ -0,0 +1,19 @@ +using EPiServer.Editor; +using EPiServer.Shell; +using AlloyTemplates.Models.Pages; + +namespace AlloyTemplates.Business.UIDescriptors +{ + /// + /// Describes how the UI should appear for content. + /// + [UIDescriptorRegistration] + public class ContainerPageUIDescriptor : UIDescriptor + { + public ContainerPageUIDescriptor() + : base(ContentTypeCssClassNames.Container) + { + DefaultView = CmsViewNames.AllPropertiesView; + } + } +} diff --git a/src/alloy/ClientResources/Images/icons/layoutIcons24x24.png b/src/alloy/ClientResources/Images/icons/layoutIcons24x24.png new file mode 100644 index 0000000..9cecefa Binary files /dev/null and b/src/alloy/ClientResources/Images/icons/layoutIcons24x24.png differ diff --git a/src/alloy/ClientResources/Scripts/Editors/StringList.js b/src/alloy/ClientResources/Scripts/Editors/StringList.js new file mode 100644 index 0000000..0f3b905 --- /dev/null +++ b/src/alloy/ClientResources/Scripts/Editors/StringList.js @@ -0,0 +1,159 @@ +/* +Dojo widget for editing a list of strings. Also see property type PropertyStringList in /Models/Properties. +*/ + +define([ + "dojo/_base/array", + "dojo/_base/connect", + "dojo/_base/declare", + "dojo/_base/lang", + + "dijit/_CssStateMixin", + "dijit/_Widget", + "dijit/_TemplatedMixin", + "dijit/_WidgetsInTemplateMixin", + + "dijit/form/Textarea", + + "epi/epi", + "epi/shell/widget/_ValueRequiredMixin" +], +function ( + array, + connect, + declare, + lang, + + _CssStateMixin, + _Widget, + _TemplatedMixin, + _WidgetsInTemplateMixin, + + Textarea, + epi, + _ValueRequiredMixin +) { + + return declare("alloy.editors.StringList", [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin, _CssStateMixin, _ValueRequiredMixin], { + + templateString: "
\ +
\ +
\ +
\ +
\ + ${helptext}\ +
", + + baseClass: "epiStringList", + + helptext: "Place items on separate lines", + + intermediateChanges: false, + + value: null, + + multiple: true, + + onChange: function (value) { + // Event + }, + + postCreate: function () { + // call base implementation + this.inherited(arguments); + + // Init textarea and bind event + this.textArea.set("intermediateChanges", this.intermediateChanges); + this.connect(this.textArea, "onChange", this._onTextAreaChanged); + }, + + isValid: function () { + // summary: + // Check if widget's value is valid. + // tags: + // protected, override + + return !this.required || lang.isArray(this.value) && this.value.length > 0 && this.value.join() !== ""; + }, + + // Setter for value property + _setValueAttr: function (value) { + this._setValue(value, true); + }, + + _getValueAttr: function () { + // summary: + // Returns the textbox value as array. + // tags: + // protected, override + + var val = this.textArea && this.textArea.get("value"); + return this._stringToList(val); + }, + + _setReadOnlyAttr: function (value) { + this._set("readOnly", value); + this.textArea.set("readOnly", value); + }, + + // Setter for intermediateChanges + _setIntermediateChangesAttr: function (value) { + this.textArea.set("intermediateChanges", value); + this._set("intermediateChanges", value); + }, + + // Event handler for textarea + _onTextAreaChanged: function (value) { + this._setValue(value, false); + }, + + _setValue: function (value, updateTextarea) { + // Assume value is an array + var list = value; + + if (typeof value === "string") { + // Split list + list = this._stringToList(value); + + } else if (!value) { + // use empty array for empty value + list = []; + } + + if (this._started && epi.areEqual(this.value, list)) { + return; + } + + // set value to this widget (and notify observers) + this._set("value", list); + + // set value to textarea + updateTextarea && this.textArea.set("value", list.join("\n")); + + if (this._started && this.validate()) { + // Trigger change event + this.onChange(list); + } + }, + + // Convert a string to a list + _stringToList: function (value) { + + // Return empty array for + if (!value || typeof value !== "string") { + return []; + } + + // Trim whitespace at start and end + var trimmed = value.replace(/^\s+|\s+$/g, ""); + + // Trim whitespace around each linebreak + var trimmedLines = trimmed.replace(/(\s*\n+\s*)/g, "\n"); + + // Split into list + var list = trimmedLines.split("\n"); + + return list; + } + }); +}); diff --git a/src/alloy/ClientResources/Styles/LayoutIcons.css b/src/alloy/ClientResources/Styles/LayoutIcons.css new file mode 100644 index 0000000..f7577fd --- /dev/null +++ b/src/alloy/ClientResources/Styles/LayoutIcons.css @@ -0,0 +1,25 @@ +.Sleek .epi-icon__layout--full { + background: url('../Images/Icons/layoutIcons24x24.png') 0px -24px no-repeat; + height: 24px; + width: 24px; +} +.Sleek .epi-icon__layout--half { + background: url('../Images/Icons/layoutIcons24x24.png') 0px -48px no-repeat; + height: 24px; + width: 24px; +} +.Sleek .epi-icon__layout--two-thirds { + background: url('../Images/Icons/layoutIcons24x24.png') 0px -72px no-repeat; + height: 24px; + width: 24px; +} +.Sleek .epi-icon__layout--one-third { + background: url('../Images/Icons/layoutIcons24x24.png') 0px -96px no-repeat; + height: 24px; + width: 24px; +} +.Sleek .epi-icon__layout--one-quarter { + background: url('../Images/Icons/layoutIcons24x24.png') 0px -120px no-repeat; + height: 24px; + width: 24px; +} diff --git a/src/alloy/ClientResources/Styles/Styles.css b/src/alloy/ClientResources/Styles/Styles.css new file mode 100644 index 0000000..f37a1c4 --- /dev/null +++ b/src/alloy/ClientResources/Styles/Styles.css @@ -0,0 +1,9 @@ +@import url("LayoutIcons.css"); + +.epiStringList .dijitTextArea { + width: 250px; +} + +.epiStringList .epiStringListError .dijitTextArea { + border: solid 1px #d46464; +} diff --git a/src/alloy/ConnectionStrings.config b/src/alloy/ConnectionStrings.config new file mode 100644 index 0000000..d1eb5f1 --- /dev/null +++ b/src/alloy/ConnectionStrings.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/alloy/Controllers/ContactBlockController.cs b/src/alloy/Controllers/ContactBlockController.cs new file mode 100644 index 0000000..a3e3fbd --- /dev/null +++ b/src/alloy/Controllers/ContactBlockController.cs @@ -0,0 +1,77 @@ +using System.Web; +using System.Web.Mvc; +using EPiServer.Core; +using AlloyTemplates.Helpers; +using AlloyTemplates.Models.Blocks; +using AlloyTemplates.Models.Pages; +using AlloyTemplates.Models.ViewModels; +using EPiServer.Web; +using EPiServer.Web.Mvc; +using EPiServer; + +namespace AlloyTemplates.Controllers +{ + public class ContactBlockController : BlockController + { + private readonly IContentLoader _contentLoader; + private readonly IPermanentLinkMapper _permanentLinkMapper; + + public ContactBlockController(IContentLoader contentLoader, IPermanentLinkMapper permanentLinkMapper) + { + _contentLoader = contentLoader; + _permanentLinkMapper = permanentLinkMapper; + } + + public override ActionResult Index(ContactBlock currentBlock) + { + ContactPage contactPage = null; + if(!ContentReference.IsNullOrEmpty(currentBlock.ContactPageLink)) + { + contactPage = _contentLoader.Get(currentBlock.ContactPageLink); + } + + var linkUrl = GetLinkUrl(currentBlock); + + var model = new ContactBlockModel + { + Heading = currentBlock.Heading, + Image = currentBlock.Image, + ContactPage = contactPage, + LinkUrl = GetLinkUrl(currentBlock), + LinkText = currentBlock.LinkText, + ShowLink = linkUrl != null + }; + + //As we're using a separate view model with different property names than the content object + //we connect the view models properties with the content objects so that they can be edited. + ViewData.GetEditHints() + .AddConnection(x => x.Heading, x => x.Heading) + .AddConnection(x => x.Image, x => x.Image) + .AddConnection(x => (object) x.ContactPage, x => (object) x.ContactPageLink) + .AddConnection(x => x.LinkText, x => x.LinkText); + + return PartialView(model); + } + + private IHtmlString GetLinkUrl(ContactBlock contactBlock) + { + if (contactBlock.LinkUrl != null && !contactBlock.LinkUrl.IsEmpty()) + { + var linkUrl = contactBlock.LinkUrl.ToString(); + + //If the url maps to a page on the site we convert it from the internal (permanent, GUID-like) format + //to the human readable and pretty public format + var linkMap = _permanentLinkMapper.Find(new UrlBuilder(linkUrl)); + if (linkMap != null && !ContentReference.IsNullOrEmpty(linkMap.ContentReference)) + { + return Url.PageLinkUrl(linkMap.ContentReference); + } + + return new MvcHtmlString(contactBlock.LinkUrl.ToString()); + } + + return null; + } + + } +} diff --git a/src/alloy/Controllers/DefaultPageController.cs b/src/alloy/Controllers/DefaultPageController.cs new file mode 100644 index 0000000..f5c4966 --- /dev/null +++ b/src/alloy/Controllers/DefaultPageController.cs @@ -0,0 +1,40 @@ +using System; +using System.Web.Mvc; +using EPiServer; +using EPiServer.Framework.DataAnnotations; +using AlloyTemplates.Models.Pages; +using AlloyTemplates.Models.ViewModels; + +namespace AlloyTemplates.Controllers +{ + /// + /// Concrete controller that handles all page types that don't have their own specific controllers. + /// + /// + /// Note that as the view file name is hard coded it won't work with DisplayModes (ie Index.mobile.cshtml). + /// For page types requiring such views add specific controllers for them. Alterntively the Index action + /// could be modified to set ControllerContext.RouteData.Values["controller"] to type name of the currentPage + /// argument. That may however have side effects. + /// + [TemplateDescriptor(Inherited = true)] + public class DefaultPageController : PageControllerBase + { + public ViewResult Index(SitePageData currentPage) + { + var model = CreateModel(currentPage); + return View(string.Format("~/Views/{0}/Index.cshtml", currentPage.GetOriginalType().Name), model); + } + + /// + /// Creates a PageViewModel where the type parameter is the type of the page. + /// + /// + /// Used to create models of a specific type without the calling method having to know that type. + /// + private static IPageViewModel CreateModel(SitePageData page) + { + var type = typeof(PageViewModel<>).MakeGenericType(page.GetOriginalType()); + return Activator.CreateInstance(type, page) as IPageViewModel; + } + } +} diff --git a/src/alloy/Controllers/ImageFileController.cs b/src/alloy/Controllers/ImageFileController.cs new file mode 100644 index 0000000..1f0b030 --- /dev/null +++ b/src/alloy/Controllers/ImageFileController.cs @@ -0,0 +1,37 @@ +using System.Web.Mvc; +using AlloyTemplates.Models.Media; +using AlloyTemplates.Models.ViewModels; +using EPiServer.Web.Mvc; +using EPiServer.Web.Routing; + +namespace AlloyTemplates.Controllers +{ + /// + /// Controller for the image file. + /// + public class ImageFileController : PartialContentController + { + private readonly UrlResolver _urlResolver; + + public ImageFileController(UrlResolver urlResolver) + { + _urlResolver = urlResolver; + } + + /// + /// The index action for the image file. Creates the view model and renders the view. + /// + /// The current image file. + public override ActionResult Index(ImageFile currentContent) + { + var model = new ImageViewModel + { + Url = _urlResolver.GetUrl(currentContent.ContentLink), + Name = currentContent.Name, + Copyright = currentContent.Copyright + }; + + return PartialView(model); + } + } +} diff --git a/src/alloy/Controllers/PageControllerBase.cs b/src/alloy/Controllers/PageControllerBase.cs new file mode 100644 index 0000000..c780542 --- /dev/null +++ b/src/alloy/Controllers/PageControllerBase.cs @@ -0,0 +1,45 @@ +using System.Web.Mvc; +using AlloyTemplates.Business; +using AlloyTemplates.Models.Pages; +using AlloyTemplates.Models.ViewModels; +using EPiServer.Web.Mvc; +using EPiServer.Shell.Security; + +namespace AlloyTemplates.Controllers +{ + /// + /// All controllers that renders pages should inherit from this class so that we can + /// apply action filters, such as for output caching site wide, should we want to. + /// + public abstract class PageControllerBase : PageController, IModifyLayout + where T : SitePageData + { + + protected EPiServer.ServiceLocation.Injected UISignInManager; + + /// + /// Signs out the current user and redirects to the Index action of the same controller. + /// + /// + /// There's a log out link in the footer which should redirect the user to the same page. + /// As we don't have a specific user/account/login controller but rely on the login URL for + /// forms authentication for login functionality we add an action for logging out to all + /// controllers inheriting from this class. + /// + public ActionResult Logout() + { + UISignInManager.Service.SignOut(); + return RedirectToAction("Index"); + } + + public virtual void ModifyLayout(LayoutModel layoutModel) + { + var page = PageContext.Page as SitePageData; + if(page != null) + { + layoutModel.HideHeader = page.HideSiteHeader; + layoutModel.HideFooter = page.HideSiteFooter; + } + } + } +} diff --git a/src/alloy/Controllers/PageListBlockController.cs b/src/alloy/Controllers/PageListBlockController.cs new file mode 100644 index 0000000..eec6ed6 --- /dev/null +++ b/src/alloy/Controllers/PageListBlockController.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using System.Linq; +using System.Web.Mvc; +using EPiServer.Core; +using EPiServer.Filters; +using AlloyTemplates.Business; +using AlloyTemplates.Models.Blocks; +using AlloyTemplates.Models.ViewModels; +using EPiServer.Web.Mvc; +using EPiServer; + +namespace AlloyTemplates.Controllers +{ + public class PageListBlockController : BlockController + { + private ContentLocator contentLocator; + private IContentLoader contentLoader; + public PageListBlockController(ContentLocator contentLocator, IContentLoader contentLoader) + { + this.contentLocator = contentLocator; + this.contentLoader = contentLoader; + } + + public override ActionResult Index(PageListBlock currentBlock) + { + var pages = FindPages(currentBlock); + + pages = Sort(pages, currentBlock.SortOrder); + + if(currentBlock.Count > 0) + { + pages = pages.Take(currentBlock.Count); + } + + var model = new PageListModel(currentBlock) + { + Pages = pages + }; + + ViewData.GetEditHints() + .AddConnection(x => x.Heading, x => x.Heading); + + return PartialView(model); + } + + private IEnumerable FindPages(PageListBlock currentBlock) + { + IEnumerable pages; + var listRoot = currentBlock.Root; + if (currentBlock.Recursive) + { + if (currentBlock.PageTypeFilter != null) + { + pages = contentLocator.FindPagesByPageType(listRoot, true, currentBlock.PageTypeFilter.ID); + } + else + { + pages = contentLocator.GetAll(listRoot); + } + } + else + { + if (currentBlock.PageTypeFilter != null) + { + pages = contentLoader.GetChildren(listRoot) + .Where(p => p.ContentTypeID == currentBlock.PageTypeFilter.ID); + } + else + { + pages = contentLoader.GetChildren(listRoot); + } + } + + if (currentBlock.CategoryFilter != null && currentBlock.CategoryFilter.Any()) + { + pages = pages.Where(x => x.Category.Intersect(currentBlock.CategoryFilter).Any()); + } + return pages; + } + + private IEnumerable Sort(IEnumerable pages, FilterSortOrder sortOrder) + { + var asCollection = new PageDataCollection(pages); + var sortFilter = new FilterSort(sortOrder); + sortFilter.Sort(asCollection); + return asCollection; + } + } +} diff --git a/src/alloy/Controllers/PreviewController.cs b/src/alloy/Controllers/PreviewController.cs new file mode 100644 index 0000000..e69f7e9 --- /dev/null +++ b/src/alloy/Controllers/PreviewController.cs @@ -0,0 +1,91 @@ +using System.Linq; +using System.Web.Mvc; +using EPiServer.Core; +using EPiServer.Framework.DataAnnotations; +using EPiServer.Framework.Web; +using AlloyTemplates.Business; +using AlloyTemplates.Models.Pages; +using AlloyTemplates.Models.ViewModels; +using EPiServer.Web; +using EPiServer.Web.Mvc; +using EPiServer; +using EPiServer.Framework.Web.Mvc; + +namespace AlloyTemplates.Controllers +{ + /* Note: as the content area rendering on Alloy is customized we create ContentArea instances + * which we render in the preview view in order to provide editors with a preview which is as + * realistic as possible. In other contexts we could simply have passed the block to the + * view and rendered it using Html.RenderContentData */ + [TemplateDescriptor( + Inherited = true, + TemplateTypeCategory = TemplateTypeCategories.MvcController, //Required as controllers for blocks are registered as MvcPartialController by default + Tags = new[] { RenderingTags.Preview, RenderingTags.Edit }, + AvailableWithoutTag = false)] + [VisitorGroupImpersonation] + [RequireClientResources] + public class PreviewController : ActionControllerBase, IRenderTemplate, IModifyLayout + { + private readonly IContentLoader _contentLoader; + private readonly TemplateResolver _templateResolver; + private readonly DisplayOptions _displayOptions; + + public PreviewController(IContentLoader contentLoader, TemplateResolver templateResolver, DisplayOptions displayOptions) + { + _contentLoader = contentLoader; + _templateResolver = templateResolver; + _displayOptions = displayOptions; + } + + public ActionResult Index(IContent currentContent) + { + //As the layout requires a page for title etc we "borrow" the start page + var startPage = _contentLoader.Get(SiteDefinition.Current.StartPage); + + var model = new PreviewModel(startPage, currentContent); + + var supportedDisplayOptions = _displayOptions + .Select(x => new { Tag = x.Tag, Name = x.Name, Supported = SupportsTag(currentContent, x.Tag) }) + .ToList(); + + if (supportedDisplayOptions.Any(x => x.Supported)) + { + foreach (var displayOption in supportedDisplayOptions) + { + var contentArea = new ContentArea(); + contentArea.Items.Add(new ContentAreaItem + { + ContentLink = currentContent.ContentLink + }); + var areaModel = new PreviewModel.PreviewArea + { + Supported = displayOption.Supported, + AreaTag = displayOption.Tag, + AreaName = displayOption.Name, + ContentArea = contentArea + }; + model.Areas.Add(areaModel); + } + } + + return View(model); + } + + private bool SupportsTag(IContent content, string tag) + { + var templateModel = _templateResolver.Resolve(HttpContext, + content.GetOriginalType(), + content, + TemplateTypeCategories.MvcPartial, + tag); + + return templateModel != null; + } + + public void ModifyLayout(LayoutModel layoutModel) + { + layoutModel.HideHeader = true; + layoutModel.HideFooter = true; + } + } +} diff --git a/src/alloy/Controllers/RegisterController.cs b/src/alloy/Controllers/RegisterController.cs new file mode 100644 index 0000000..9a64fdf --- /dev/null +++ b/src/alloy/Controllers/RegisterController.cs @@ -0,0 +1,117 @@ +using AlloyTemplates.Models; +using EPiServer.Core; +using EPiServer.ServiceLocation; +using EPiServer.Shell.Security; +using EPiServer.Web.Routing; +using System.Collections.Generic; +using System.Linq; +using System.Web.Mvc; +using System.Web.Profile; +using EPiServer.Security; +using EPiServer.DataAbstraction; +using EPiServer.Personalization; + +namespace AlloyTemplates.Controllers +{ + /// + /// Used to register a user for first time + /// + public class RegisterController : Controller + { + const string AdminRoleName = "WebAdmins"; + public const string ErrorKey = "CreateError"; + + public ActionResult Index() + { + return View(); + } + + // + // POST: /Register + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + [ValidateInput(false)] + public ActionResult Index(RegisterViewModel model) + { + if (ModelState.IsValid) + { + UIUserCreateStatus status; + IEnumerable errors = Enumerable.Empty(); + var result = UIUserProvider.CreateUser(model.Username, model.Password, model.Email, null, null, true, out status, out errors); + if (status == UIUserCreateStatus.Success) + { + UIRoleProvider.CreateRole(AdminRoleName); + UIRoleProvider.AddUserToRoles(result.Username, new string[] { AdminRoleName }); + + if (ProfileManager.Enabled) + { + var profile = EPiServerProfile.Wrap(ProfileBase.Create(result.Username)); + profile.Email = model.Email; + profile.Save(); + } + + AdministratorRegistrationPage.IsEnabled = false; + SetFullAccessToWebAdmin(); + var resFromSignIn = UISignInManager.SignIn(UIUserProvider.Name, model.Username, model.Password); + if (resFromSignIn) + { + return Redirect(UrlResolver.Current.GetUrl(ContentReference.StartPage)); + } + } + AddErrors(errors); + } + // If we got this far, something failed, redisplay form + return View(model); + } + + private void SetFullAccessToWebAdmin() + { + var securityrep = ServiceLocator.Current.GetInstance(); + var permissions = securityrep.Get(ContentReference.RootPage).CreateWritableClone() as IContentSecurityDescriptor; + permissions.AddEntry(new AccessControlEntry(AdminRoleName, AccessLevel.FullAccess)); + securityrep.Save(ContentReference.RootPage, permissions, SecuritySaveType.Replace); + } + + private void AddErrors(IEnumerable errors) + { + foreach (var error in errors) + { + ModelState.AddModelError(ErrorKey, error); + } + } + + protected override void OnAuthorization(AuthorizationContext filterContext) + { + if (!AdministratorRegistrationPage.IsEnabled) + { + filterContext.Result = new HttpNotFoundResult(); + return; + } + base.OnAuthorization(filterContext); + } + + UIUserProvider UIUserProvider + { + get + { + return ServiceLocator.Current.GetInstance(); + } + } + UIRoleProvider UIRoleProvider + { + get + { + return ServiceLocator.Current.GetInstance(); + } + } + UISignInManager UISignInManager + { + get + { + return ServiceLocator.Current.GetInstance(); + } + } + + } +} diff --git a/src/alloy/Controllers/SearchPageController.cs b/src/alloy/Controllers/SearchPageController.cs new file mode 100644 index 0000000..1572c82 --- /dev/null +++ b/src/alloy/Controllers/SearchPageController.cs @@ -0,0 +1,106 @@ +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using EPiServer.Core; +using EPiServer.Framework.Web; +using EPiServer.Search; +using AlloyTemplates.Business; +using AlloyTemplates.Models.Pages; +using AlloyTemplates.Models.ViewModels; +using EPiServer.Web; +using EPiServer.Web.Hosting; +using EPiServer.Web.Mvc.Html; +using EPiServer.Web.Routing; + +namespace AlloyTemplates.Controllers +{ + public class SearchPageController : PageControllerBase + { + private const int MaxResults = 40; + private readonly SearchService _searchService; + private readonly ContentSearchHandler _contentSearchHandler; + private readonly UrlResolver _urlResolver; + private readonly TemplateResolver _templateResolver; + + public SearchPageController( + SearchService searchService, + ContentSearchHandler contentSearchHandler, + TemplateResolver templateResolver, + UrlResolver urlResolver) + { + _searchService = searchService; + _contentSearchHandler = contentSearchHandler; + _templateResolver = templateResolver; + _urlResolver = urlResolver; + } + + [ValidateInput(false)] + public ViewResult Index(SearchPage currentPage, string q) + { + var model = new SearchContentModel(currentPage) + { + SearchServiceDisabled = !_searchService.IsActive, + SearchedQuery = q + }; + + if(!string.IsNullOrWhiteSpace(q) && _searchService.IsActive) + { + var hits = Search(q.Trim(), + new[] { SiteDefinition.Current.StartPage, SiteDefinition.Current.GlobalAssetsRoot, SiteDefinition.Current.SiteAssetsRoot }, + ControllerContext.HttpContext, + currentPage.Language?.Name).ToList(); + model.Hits = hits; + model.NumberOfHits = hits.Count(); + } + + return View(model); + } + + /// + /// Performs a search for pages and media and maps each result to the view model class SearchHit. + /// + /// + /// The search functionality is handled by the injected SearchService in order to keep the controller simple. + /// Uses EPiServer Search. For more advanced search functionality such as keyword highlighting, + /// facets and search statistics consider using EPiServer Find. + /// + private IEnumerable Search(string searchText, IEnumerable searchRoots, HttpContextBase context, string languageBranch) + { + var searchResults = _searchService.Search(searchText, searchRoots, context, languageBranch, MaxResults); + + return searchResults.IndexResponseItems.SelectMany(CreateHitModel); + } + + private IEnumerable CreateHitModel(IndexResponseItem responseItem) + { + var content = _contentSearchHandler.GetContent(responseItem); + if (content != null && HasTemplate(content) && IsPublished(content as IVersionable)) + { + yield return CreatePageHit(content); + } + } + + private bool HasTemplate(IContent content) + { + return _templateResolver.HasTemplate(content, TemplateTypeCategories.Page); + } + + private bool IsPublished(IVersionable content) + { + if (content == null) + return true; + return content.Status.HasFlag(VersionStatus.Published); + } + + private SearchContentModel.SearchHit CreatePageHit(IContent content) + { + return new SearchContentModel.SearchHit + { + Title = content.Name, + Url = _urlResolver.GetUrl(content.ContentLink), + Excerpt = content is SitePageData ? ((SitePageData) content).TeaserText : string.Empty + }; + } + } +} diff --git a/src/alloy/Controllers/StartPageController.cs b/src/alloy/Controllers/StartPageController.cs new file mode 100644 index 0000000..ce8515b --- /dev/null +++ b/src/alloy/Controllers/StartPageController.cs @@ -0,0 +1,30 @@ +using System.Web.Mvc; +using AlloyTemplates.Models.Pages; +using AlloyTemplates.Models.ViewModels; +using EPiServer.Web; +using EPiServer.Web.Mvc; + +namespace AlloyTemplates.Controllers +{ + public class StartPageController : PageControllerBase + { + public ActionResult Index(StartPage currentPage) + { + var model = PageViewModel.Create(currentPage); + + if (SiteDefinition.Current.StartPage.CompareToIgnoreWorkID(currentPage.ContentLink)) // Check if it is the StartPage or just a page of the StartPage type. + { + //Connect the view models logotype property to the start page's to make it editable + var editHints = ViewData.GetEditHints, StartPage>(); + editHints.AddConnection(m => m.Layout.Logotype, p => p.SiteLogotype); + editHints.AddConnection(m => m.Layout.ProductPages, p => p.ProductPageLinks); + editHints.AddConnection(m => m.Layout.CompanyInformationPages, p => p.CompanyInformationPageLinks); + editHints.AddConnection(m => m.Layout.NewsPages, p => p.NewsPageLinks); + editHints.AddConnection(m => m.Layout.CustomerZonePages, p => p.CustomerZonePageLinks); + } + + return View(model); + } + + } +} diff --git a/src/alloy/Controllers/VideoFileController.cs b/src/alloy/Controllers/VideoFileController.cs new file mode 100644 index 0000000..323e3a0 --- /dev/null +++ b/src/alloy/Controllers/VideoFileController.cs @@ -0,0 +1,38 @@ +using System.Web.Mvc; +using AlloyTemplates.Models.Media; +using AlloyTemplates.Models.ViewModels; +using EPiServer.Web.Mvc; +using EPiServer.Web.Routing; +using System; +using EPiServer.Core; + +namespace AlloyTemplates.Controllers +{ + /// + /// Controller for the video file. + /// + public class VideoFileController : PartialContentController + { + private readonly UrlResolver _urlResolver; + + public VideoFileController(UrlResolver urlResolver) + { + _urlResolver = urlResolver; + } + + /// + /// The index action for the video file. Creates the view model and renders the view. + /// + /// The current video file. + public override ActionResult Index(VideoFile currentContent) + { + var model = new VideoViewModel + { + Url = _urlResolver.GetUrl(currentContent.ContentLink), + PreviewImageUrl = ContentReference.IsNullOrEmpty(currentContent.PreviewImage) ? String.Empty : _urlResolver.GetUrl(currentContent.PreviewImage), + }; + + return PartialView(model); + } + } +} diff --git a/src/alloy/EPiServer.Labs.BlockEnhancements.nuspec b/src/alloy/EPiServer.Labs.BlockEnhancements.nuspec new file mode 100644 index 0000000..9e0512a --- /dev/null +++ b/src/alloy/EPiServer.Labs.BlockEnhancements.nuspec @@ -0,0 +1,28 @@ + + + + EPiServer.Labs.BlockEnhancements + $version$ + EPiServer.Labs.BlockEnhancements + EPiServer Labs + EPiServer Labs + false + Collection of useful enhancements around Block Publishing process. + + Copyright 2019 + content block publishing publish local + https://raw.githubusercontent.com/episerver/episerver.labs.blockenhancements/master/LICENSE + http://www.episerver.com/Framework/Styles/Images/Products/Content.png + https://github.com/episerver/episerver.labs.blockenhancements + + + + + + + + + + + + \ No newline at end of file diff --git a/src/alloy/EPiServerFramework.config b/src/alloy/EPiServerFramework.config new file mode 100644 index 0000000..e488729 --- /dev/null +++ b/src/alloy/EPiServerFramework.config @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/alloy/Global.asax.cs b/src/alloy/Global.asax.cs new file mode 100644 index 0000000..dcfbbf3 --- /dev/null +++ b/src/alloy/Global.asax.cs @@ -0,0 +1,7 @@ +namespace AlloyTemplates +{ + public class EPiServerApplication : EPiServer.Global + { + + } +} diff --git a/src/alloy/Global.cs b/src/alloy/Global.cs new file mode 100644 index 0000000..95ac1ca --- /dev/null +++ b/src/alloy/Global.cs @@ -0,0 +1,87 @@ +using EPiServer.DataAnnotations; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace AlloyTemplates +{ + + public class Global + { + public static readonly string LoginPath = "/util/login.aspx"; + public static readonly string AppRelativeLoginPath = string.Format("~{0}", LoginPath); + + /// + /// Group names for content types and properties + /// + [GroupDefinitions()] + public static class GroupNames + { + [Display(Name = "Contact", Order = 1)] + public const string Contact = "Contact"; + + [Display(Name = "Default", Order = 2)] + public const string Default = "Default"; + + [Display(Name = "Metadata", Order = 3)] + public const string MetaData = "Metadata"; + + [Display(Name = "News", Order = 4)] + public const string News = "News"; + + [Display(Name = "Products", Order = 5)] + public const string Products = "Products"; + + [Display(Name = "SiteSettings", Order = 6)] + public const string SiteSettings = "SiteSettings"; + + [Display(Name = "Specialized", Order = 7)] + public const string Specialized = "Specialized"; + } + + /// + /// Tags to use for the main widths used in the Bootstrap HTML framework + /// + public static class ContentAreaTags + { + public const string FullWidth = "span12"; + public const string TwoThirdsWidth = "span8"; + public const string HalfWidth = "span6"; + public const string OneThirdWidth = "span4"; + public const string NoRenderer = "norenderer"; + } + + /// + /// Main widths used in the Bootstrap HTML framework + /// + public static class ContentAreaWidths + { + public const int FullWidth = 12; + public const int TwoThirdsWidth = 8; + public const int HalfWidth = 6; + public const int OneThirdWidth = 4; + } + + public static Dictionary ContentAreaTagWidths = new Dictionary + { + { ContentAreaTags.FullWidth, ContentAreaWidths.FullWidth }, + { ContentAreaTags.TwoThirdsWidth, ContentAreaWidths.TwoThirdsWidth }, + { ContentAreaTags.HalfWidth, ContentAreaWidths.HalfWidth }, + { ContentAreaTags.OneThirdWidth, ContentAreaWidths.OneThirdWidth } + }; + + /// + /// Names used for UIHint attributes to map specific rendering controls to page properties + /// + public static class SiteUIHints + { + public const string Contact = "contact"; + public const string Strings = "StringList"; + public const string StringsCollection = "StringsCollection"; + } + + /// + /// Virtual path to folder with static graphics, such as "~/Static/gfx/" + /// + public const string StaticGraphicsFolderPath = "~/Static/gfx/"; + } +} diff --git a/src/alloy/Helpers/CategorizableExtensions.cs b/src/alloy/Helpers/CategorizableExtensions.cs new file mode 100644 index 0000000..40284c1 --- /dev/null +++ b/src/alloy/Helpers/CategorizableExtensions.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.Linq; +using EPiServer; +using EPiServer.Core; +using EPiServer.DataAbstraction; +using EPiServer.ServiceLocation; + +namespace AlloyTemplates.Helpers +{ + /// + /// Provides extension methods for categorizable content + /// + /// ICategorizable content includes for example pages and blocks. + public static class CategorizableExtensions + { + /// + /// Returns the CSS classes (if any) associated with the theme(s) of the content, as decided by its categories + /// + /// + /// CSS classes associated with the content's theme(s), or an empty string array if no theme is applicable + /// Content's categorization may map to more than one theme. This method assumes there are website categories called "Meet", "Track", and "Plan" + public static string[] GetThemeCssClassNames(this ICategorizable content) + { + if (content.Category == null) + { + return new string[0]; + } + + var cssClasses = new HashSet(); // Although with some overhead, a HashSet allows us to ensure we never add a CSS class more than once + var categoryRepository = ServiceLocator.Current.GetInstance(); + + foreach (var categoryName in content.Category.Select(category => categoryRepository.Get(category).Name.ToLower())) + { + switch (categoryName) + { + case "meet": + cssClasses.Add("theme1"); + break; + case "track": + cssClasses.Add("theme2"); + break; + case "plan": + cssClasses.Add("theme3"); + break; + } + } + + return cssClasses.ToArray(); + } + } +} diff --git a/src/alloy/Helpers/HtmlHelpers.cs b/src/alloy/Helpers/HtmlHelpers.cs new file mode 100644 index 0000000..b10e016 --- /dev/null +++ b/src/alloy/Helpers/HtmlHelpers.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Web; +using System.Web.Mvc; +using System.Web.WebPages; +using EPiServer.Core; +using EPiServer.ServiceLocation; +using AlloyTemplates.Business; +using EPiServer.Web.Mvc.Html; +using EPiServer.Web.Routing; +using EPiServer; + +namespace AlloyTemplates.Helpers +{ + public static class HtmlHelpers + { + /// + /// Returns an element for each child page of the rootLink using the itemTemplate. + /// + /// The html helper in whose context the list should be created + /// A reference to the root whose children should be listed + /// A template for each page which will be used to produce the return value. Can be either a delegate or a Razor helper. + /// Wether an element for the root page should be returned + /// Wether pages that do not have the "Display in navigation" checkbox checked should be excluded + /// Wether page that do not have a template (i.e. container pages) should be excluded + /// + /// Filter by access rights and publication status. + /// + public static IHtmlString MenuList( + this HtmlHelper helper, + ContentReference rootLink, + Func itemTemplate = null, + bool includeRoot = false, + bool requireVisibleInMenu = true, + bool requirePageTemplate = true) + { + itemTemplate = itemTemplate ?? GetDefaultItemTemplate(helper); + var currentContentLink = helper.ViewContext.RequestContext.GetContentLink(); + var contentLoader = ServiceLocator.Current.GetInstance(); + + Func, IEnumerable> filter = + pages => pages.FilterForDisplay(requirePageTemplate, requireVisibleInMenu); + + var pagePath = contentLoader.GetAncestors(currentContentLink) + .Reverse() + .Select(x => x.ContentLink) + .SkipWhile(x => !x.CompareToIgnoreWorkID(rootLink)) + .ToList(); + + var menuItems = contentLoader.GetChildren(rootLink) + .FilterForDisplay(requirePageTemplate, requireVisibleInMenu) + .Select(x => CreateMenuItem(x, currentContentLink, pagePath, contentLoader, filter)) + .ToList(); + + if(includeRoot) + { + menuItems.Insert(0, CreateMenuItem(contentLoader.Get(rootLink), currentContentLink, pagePath, contentLoader, filter)); + } + + var buffer = new StringBuilder(); + var writer = new StringWriter(buffer); + foreach (var menuItem in menuItems) + { + itemTemplate(menuItem).WriteTo(writer); + } + + return new MvcHtmlString(buffer.ToString()); + } + + private static MenuItem CreateMenuItem(PageData page, ContentReference currentContentLink, List pagePath, IContentLoader contentLoader, Func, IEnumerable> filter) + { + var menuItem = new MenuItem(page) + { + Selected = page.ContentLink.CompareToIgnoreWorkID(currentContentLink) || + pagePath.Contains(page.ContentLink), + HasChildren = + new Lazy(() => filter(contentLoader.GetChildren(page.ContentLink)).Any()) + }; + return menuItem; + } + + private static Func GetDefaultItemTemplate(HtmlHelper helper) + { + return x => new HelperResult(writer => writer.Write(helper.PageLink(x.Page))); + } + + public class MenuItem + { + public MenuItem(PageData page) + { + Page = page; + } + public PageData Page { get; set; } + public bool Selected { get; set; } + public Lazy HasChildren { get; set; } + } + + /// + /// Writes an opening ]]> tag to the response if the shouldWriteLink argument is true. + /// Returns a ConditionalLink object which when disposed will write a closing ]]> tag + /// to the response if the shouldWriteLink argument is true. + /// + public static ConditionalLink BeginConditionalLink(this HtmlHelper helper, bool shouldWriteLink, IHtmlString url, string title = null, string cssClass = null) + { + if(shouldWriteLink) + { + var linkTag = new TagBuilder("a"); + linkTag.Attributes.Add("href", url.ToHtmlString()); + + if(!string.IsNullOrWhiteSpace(title)) + { + linkTag.Attributes.Add("title", helper.Encode(title)); + } + + if (!string.IsNullOrWhiteSpace(cssClass)) + { + linkTag.Attributes.Add("class", cssClass); + } + + helper.ViewContext.Writer.Write(linkTag.ToString(TagRenderMode.StartTag)); + } + return new ConditionalLink(helper.ViewContext, shouldWriteLink); + } + + /// + /// Writes an opening ]]> tag to the response if the shouldWriteLink argument is true. + /// Returns a ConditionalLink object which when disposed will write a closing ]]> tag + /// to the response if the shouldWriteLink argument is true. + /// + /// + /// Overload which only executes the delegate for retrieving the URL if the link should be written. + /// This may be used to prevent null reference exceptions by adding null checkes to the shouldWriteLink condition. + /// + public static ConditionalLink BeginConditionalLink(this HtmlHelper helper, bool shouldWriteLink, Func urlGetter, string title = null, string cssClass = null) + { + IHtmlString url = MvcHtmlString.Empty; + + if(shouldWriteLink) + { + url = urlGetter(); + } + + return helper.BeginConditionalLink(shouldWriteLink, url, title, cssClass); + } + + public class ConditionalLink : IDisposable + { + private readonly ViewContext _viewContext; + private readonly bool _linked; + private bool _disposed; + + public ConditionalLink(ViewContext viewContext, bool isLinked) + { + _viewContext = viewContext; + _linked = isLinked; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + _disposed = true; + + if (_linked) + { + _viewContext.Writer.Write(""); + } + } + } + } +} diff --git a/src/alloy/Helpers/UrlHelpers.cs b/src/alloy/Helpers/UrlHelpers.cs new file mode 100644 index 0000000..2c7e716 --- /dev/null +++ b/src/alloy/Helpers/UrlHelpers.cs @@ -0,0 +1,68 @@ +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; +using EPiServer.Core; +using EPiServer.Globalization; +using EPiServer.ServiceLocation; +using EPiServer.Web.Routing; +using EPiServer; + +namespace AlloyTemplates.Helpers +{ + public static class UrlHelpers + { + /// + /// Returns the target URL for a ContentReference. Respects the page's shortcut setting + /// so if the page is set as a shortcut to another page or an external URL that URL + /// will be returned. + /// + public static IHtmlString PageLinkUrl(this UrlHelper urlHelper, ContentReference contentLink) + { + if(ContentReference.IsNullOrEmpty(contentLink)) + { + return MvcHtmlString.Empty; + } + + var contentLoader = ServiceLocator.Current.GetInstance(); + var page = contentLoader.Get(contentLink); + + return PageLinkUrl(urlHelper, page); + } + + /// + /// Returns the target URL for a page. Respects the page's shortcut setting + /// so if the page is set as a shortcut to another page or an external URL that URL + /// will be returned. + /// + public static IHtmlString PageLinkUrl(this UrlHelper urlHelper, PageData page) + { + var urlResolver = ServiceLocator.Current.GetInstance(); + switch (page.LinkType) + { + case PageShortcutType.Normal: + case PageShortcutType.FetchData: + return new MvcHtmlString(urlResolver.GetUrl(page.ContentLink)); + + case PageShortcutType.Shortcut: + var shortcutProperty = page.Property["PageShortcutLink"] as PropertyPageReference; + if (shortcutProperty != null && !ContentReference.IsNullOrEmpty(shortcutProperty.ContentLink)) + { + return urlHelper.PageLinkUrl(shortcutProperty.ContentLink); + } + break; + + case PageShortcutType.External: + return new MvcHtmlString(page.LinkURL); + } + return MvcHtmlString.Empty; + } + + public static RouteValueDictionary GetPageRoute(this RequestContext requestContext, ContentReference contentLink) + { + var values = new RouteValueDictionary(); + values[RoutingConstants.NodeKey] = contentLink; + values[RoutingConstants.LanguageKey] = ContentLanguage.PreferredCulture.Name; + return values; + } + } +} diff --git a/src/alloy/IndexingService/IndexingService.svc b/src/alloy/IndexingService/IndexingService.svc new file mode 100644 index 0000000..43755c8 --- /dev/null +++ b/src/alloy/IndexingService/IndexingService.svc @@ -0,0 +1,17 @@ +<%@ ServiceHost Language="C#" Debug="false" Service="EPiServer.Search.IndexingService.IndexingService" Factory="IndexingServiceHostFactory" %> + +using System.ServiceModel; +using System.ServiceModel.Activation; + +public class IndexingServiceHostFactory : WebServiceHostFactory +{ + protected override ServiceHost CreateServiceHost(System.Type serviceType, System.Uri[] baseAddresses) + { + var host = base.CreateServiceHost(serviceType, baseAddresses); + + WebHttpBinding binding = new WebHttpBinding("IndexingServiceCustomBinding"); + var endpoint = host.AddServiceEndpoint(typeof(EPiServer.Search.IndexingService.IIndexingService), binding, ""); + + return host; + } +} diff --git a/src/alloy/Models/Blocks/ButtonBlock.cs b/src/alloy/Models/Blocks/ButtonBlock.cs new file mode 100644 index 0000000..7afa5b0 --- /dev/null +++ b/src/alloy/Models/Blocks/ButtonBlock.cs @@ -0,0 +1,22 @@ +using System.ComponentModel.DataAnnotations; +using EPiServer.DataAbstraction; +using EPiServer; + +namespace AlloyTemplates.Models.Blocks +{ + /// + /// Used to insert a link which is styled as a button + /// + [SiteContentType(GUID = "426CF12F-1F01-4EA0-922F-0778314DDAF0")] + [SiteImageUrl] + public class ButtonBlock : SiteBlockData + { + [Display(Order = 1, GroupName = SystemTabNames.Content)] + [Required] + public virtual string ButtonText { get; set; } + + [Display(Order = 2, GroupName = SystemTabNames.Content)] + [Required] + public virtual Url ButtonLink { get; set; } + } +} diff --git a/src/alloy/Models/Blocks/ContactBlock.cs b/src/alloy/Models/Blocks/ContactBlock.cs new file mode 100644 index 0000000..353e741 --- /dev/null +++ b/src/alloy/Models/Blocks/ContactBlock.cs @@ -0,0 +1,52 @@ +using System.ComponentModel.DataAnnotations; +using EPiServer.Core; +using EPiServer.DataAbstraction; +using EPiServer.DataAnnotations; +using EPiServer.Web; +using EPiServer; + +namespace AlloyTemplates.Models.Blocks +{ + /// + /// Used to present contact information with a call-to-action link + /// + /// Actual contact details are retrieved from a contact page specified using the ContactPageLink property + [SiteContentType(GUID = "7E932EAF-6BC2-4753-902A-8670EDC5F363")] + [SiteImageUrl] + public class ContactBlock : SiteBlockData + { + [Display( + GroupName = SystemTabNames.Content, + Order = 1)] + [CultureSpecific] + [UIHint(UIHint.Image)] + public virtual ContentReference Image { get; set; } + + [Display( + GroupName = SystemTabNames.Content, + Order = 2)] + [CultureSpecific] + public virtual string Heading { get; set; } + + /// + /// Gets or sets the contact page from which contact information should be retrieved + /// + [Display( + GroupName = SystemTabNames.Content, + Order = 3)] + [UIHint(Global.SiteUIHints.Contact)] + public virtual PageReference ContactPageLink { get; set; } + + [Display( + GroupName = SystemTabNames.Content, + Order = 4)] + [CultureSpecific] + public virtual string LinkText { get; set; } + + [Display( + GroupName = SystemTabNames.Content, + Order = 5)] + [CultureSpecific] + public virtual Url LinkUrl { get; set; } + } +} diff --git a/src/alloy/Models/Blocks/EditorialBlock.cs b/src/alloy/Models/Blocks/EditorialBlock.cs new file mode 100644 index 0000000..84c68f7 --- /dev/null +++ b/src/alloy/Models/Blocks/EditorialBlock.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; +using EPiServer.Core; +using EPiServer.DataAbstraction; +using EPiServer.DataAnnotations; + +namespace AlloyTemplates.Models.Blocks +{ + /// + /// Used to insert editorial content edited using a rich-text editor + /// + [SiteContentType( + GUID = "67F617A4-2175-4360-975E-75EDF2B924A7", + GroupName = SystemTabNames.Content)] + [SiteImageUrl] + public class EditorialBlock : SiteBlockData + { + [Display(GroupName = SystemTabNames.Content)] + [CultureSpecific] + public virtual XhtmlString MainBody { get; set; } + } +} diff --git a/src/alloy/Models/Blocks/JumbotronBlock.cs b/src/alloy/Models/Blocks/JumbotronBlock.cs new file mode 100644 index 0000000..e115eb5 --- /dev/null +++ b/src/alloy/Models/Blocks/JumbotronBlock.cs @@ -0,0 +1,80 @@ +using System.ComponentModel.DataAnnotations; +using EPiServer.DataAbstraction; +using EPiServer.DataAnnotations; +using EPiServer.Web; +using EPiServer.Core; +using EPiServer; + +namespace AlloyTemplates.Models.Blocks +{ + /// + /// Used for a primary message on a page, commonly used on start pages and landing pages + /// + [SiteContentType( + GroupName = Global.GroupNames.Specialized, + GUID = "9FD1C860-7183-4122-8CD4-FF4C55E096F9")] + [SiteImageUrl] + public class JumbotronBlock : SiteBlockData + { + [Display( + GroupName = SystemTabNames.Content, + Order = 1 + )] + [CultureSpecific] + [UIHint(UIHint.Image)] + public virtual ContentReference Image { get; set; } + + /// + /// Gets or sets a description for the image, for example used as the alt text for the image when rendered + /// + [Display( + GroupName = SystemTabNames.Content, + Order = 1 + )] + [CultureSpecific] + [UIHint(UIHint.Textarea)] + public virtual string ImageDescription + { + get + { + var propertyValue = this["ImageDescription"] as string; + + // Return image description with fall back to the heading if no description has been specified + return string.IsNullOrWhiteSpace(propertyValue) ? Heading : propertyValue; + } + set { this["ImageDescription"] = value; } + } + + [Display( + GroupName = SystemTabNames.Content, + Order = 1 + )] + [CultureSpecific] + public virtual string Heading { get; set; } + + [Display( + GroupName = SystemTabNames.Content, + Order = 2 + )] + [CultureSpecific] + [UIHint(UIHint.Textarea)] + public virtual string SubHeading { get; set; } + + [Display( + GroupName = SystemTabNames.Content, + Order = 3 + )] + [CultureSpecific] + [Required] + public virtual string ButtonText { get; set; } + + //The link must be required as an anchor tag requires an href in order to be valid and focusable + [Display( + GroupName = SystemTabNames.Content, + Order = 4 + )] + [CultureSpecific] + [Required] + public virtual Url ButtonLink { get; set; } + } +} diff --git a/src/alloy/Models/Blocks/PageListBlock.cs b/src/alloy/Models/Blocks/PageListBlock.cs new file mode 100644 index 0000000..78ca3a7 --- /dev/null +++ b/src/alloy/Models/Blocks/PageListBlock.cs @@ -0,0 +1,92 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using EPiServer.Core; +using EPiServer.DataAbstraction; +using EPiServer.DataAnnotations; +using EPiServer.Filters; + +namespace AlloyTemplates.Models.Blocks +{ + /// + /// Used to insert a list of pages, for example a news list + /// + [SiteContentType(GUID = "30685434-33DE-42AF-88A7-3126B936AEAD")] + [SiteImageUrl] + public class PageListBlock : SiteBlockData + { + [Display( + GroupName = SystemTabNames.Content, + Order = 1)] + [CultureSpecific] + public virtual string Heading { get; set; } + + [Display( + GroupName = SystemTabNames.Content, + Order = 2)] + [DefaultValue(false)] + public virtual bool IncludePublishDate { get; set; } + + /// + /// Gets or sets whether a page introduction/description should be included in the list + /// + [Display( + GroupName = SystemTabNames.Content, + Order = 3)] + [DefaultValue(true)] + public virtual bool IncludeIntroduction { get; set; } + + [Display( + GroupName = SystemTabNames.Content, + Order = 4)] + [DefaultValue(3)] + [Required] + public virtual int Count { get; set; } + + [Display( + GroupName = SystemTabNames.Content, + Order = 4)] + [DefaultValue(FilterSortOrder.PublishedDescending)] + [UIHint("SortOrder")] + [BackingType(typeof(PropertyNumber))] + public virtual FilterSortOrder SortOrder { get; set; } + + [Display( + GroupName = SystemTabNames.Content, + Order = 5)] + [Required] + public virtual PageReference Root { get; set; } + + [Display( + GroupName = SystemTabNames.Content, + Order = 6)] + public virtual PageType PageTypeFilter{get; set;} + + [Display( + GroupName = SystemTabNames.Content, + Order = 7)] + public virtual CategoryList CategoryFilter { get; set; } + + [Display( + GroupName = SystemTabNames.Content, + Order = 8)] + public virtual bool Recursive { get; set; } + + #region IInitializableContent + + /// + /// Sets the default property values on the content data. + /// + /// Type of the content. + public override void SetDefaultValues(ContentType contentType) + { + base.SetDefaultValues(contentType); + + Count = 3; + IncludeIntroduction = true; + IncludePublishDate = false; + SortOrder = FilterSortOrder.PublishedDescending; + } + + #endregion + } +} diff --git a/src/alloy/Models/Blocks/SiteBlockData.cs b/src/alloy/Models/Blocks/SiteBlockData.cs new file mode 100644 index 0000000..444bdf2 --- /dev/null +++ b/src/alloy/Models/Blocks/SiteBlockData.cs @@ -0,0 +1,10 @@ + +namespace AlloyTemplates.Models.Blocks +{ + /// + /// Base class for all block types on the site + /// + public abstract class SiteBlockData : EPiServer.Core.BlockData + { + } +} diff --git a/src/alloy/Models/Blocks/SiteLogotypeBlock.cs b/src/alloy/Models/Blocks/SiteLogotypeBlock.cs new file mode 100644 index 0000000..61deb35 --- /dev/null +++ b/src/alloy/Models/Blocks/SiteLogotypeBlock.cs @@ -0,0 +1,44 @@ +using System.ComponentModel.DataAnnotations; +using EPiServer.Core; +using EPiServer.DataAnnotations; +using EPiServer.Shell.ObjectEditing; +using EPiServer.Web; +using EPiServer; + +namespace AlloyTemplates.Models.Blocks +{ + /// + /// Used to provide a composite property on the start page to set site logotype settings + /// + [SiteContentType( + GUID = "09854019-91A5-4B93-8623-17F038346001", + AvailableInEditMode = false)] // Should not be created and added to content areas by editors, the SiteLogotypeBlock is only used as a property type + [SiteImageUrl] + public class SiteLogotypeBlock : SiteBlockData + { + /// + /// Gets the site logotype URL + /// + /// If not specified a default logotype will be used + [DefaultDragAndDropTarget] + [UIHint(UIHint.Image)] + public virtual Url Url + { + get + { + var url = this.GetPropertyValue(b => b.Url); + + return url == null || url.IsEmpty() + ? new Url("/Static/gfx/logotype.png") + : url; + } + set + { + this.SetPropertyValue(b => b.Url, value); + } + } + + [CultureSpecific] + public virtual string Title { get; set; } + } +} diff --git a/src/alloy/Models/Blocks/TeaserBlock.cs b/src/alloy/Models/Blocks/TeaserBlock.cs new file mode 100644 index 0000000..f5ea8e2 --- /dev/null +++ b/src/alloy/Models/Blocks/TeaserBlock.cs @@ -0,0 +1,44 @@ +using System.ComponentModel.DataAnnotations; +using EPiServer.Core; +using EPiServer.DataAbstraction; +using EPiServer.DataAnnotations; +using EPiServer.Web; + +namespace AlloyTemplates.Models.Blocks +{ + /// + /// Used to provide a stylized entry point to a page on the site + /// + [SiteContentType(GUID = "EB67A99A-E239-41B8-9C59-20EAA5936047")] // BEST PRACTICE TIP: Always assign a GUID explicitly when creating a new block type + [SiteImageUrl] // Use site's default thumbnail + public class TeaserBlock : SiteBlockData + { + [CultureSpecific] + [Required(AllowEmptyStrings = false)] + [Display( + GroupName = SystemTabNames.Content, + Order = 1)] + public virtual string Heading { get; set; } + + [CultureSpecific] + [Required(AllowEmptyStrings = false)] + [Display( + GroupName = SystemTabNames.Content, + Order = 2)] + [UIHint(UIHint.Textarea)] + public virtual string Text { get; set; } + + [CultureSpecific] + [Required(AllowEmptyStrings = false)] + [UIHint(UIHint.Image)] + [Display( + GroupName = SystemTabNames.Content, + Order = 3)] + public virtual ContentReference Image { get; set; } + + [Display( + GroupName = SystemTabNames.Content, + Order = 4)] + public virtual PageReference Link { get; set; } + } +} diff --git a/src/alloy/Models/Blocks/_ReadMe.txt b/src/alloy/Models/Blocks/_ReadMe.txt new file mode 100644 index 0000000..e1d48ff --- /dev/null +++ b/src/alloy/Models/Blocks/_ReadMe.txt @@ -0,0 +1,6 @@ +This folder contains all block types. + +Blocks should be named with a suffix of "Block", such as "TeaserBlock" or "NewsListBlock". + +Default block controls should be named with a suffix of "Control", +such as "TeaserBlockControl" or "NewsListBlockControl". diff --git a/src/alloy/Models/Media/GenericMedia.cs b/src/alloy/Models/Media/GenericMedia.cs new file mode 100644 index 0000000..e8fc983 --- /dev/null +++ b/src/alloy/Models/Media/GenericMedia.cs @@ -0,0 +1,15 @@ +using EPiServer.Core; +using EPiServer.DataAnnotations; +using System; + +namespace AlloyTemplates.Models.Media +{ + [ContentType(GUID = "EE3BD195-7CB0-4756-AB5F-E5E223CD9820")] + public class GenericMedia : MediaData + { + /// + /// Gets or sets the description. + /// + public virtual String Description { get; set; } + } +} diff --git a/src/alloy/Models/Media/ImageFile.cs b/src/alloy/Models/Media/ImageFile.cs new file mode 100644 index 0000000..3bd0594 --- /dev/null +++ b/src/alloy/Models/Media/ImageFile.cs @@ -0,0 +1,20 @@ +using EPiServer.Core; +using EPiServer.DataAnnotations; +using EPiServer.Framework.DataAnnotations; +using System.ComponentModel.DataAnnotations; + +namespace AlloyTemplates.Models.Media +{ + [ContentType(GUID = "0A89E464-56D4-449F-AEA8-2BF774AB8730")] + [MediaDescriptor(ExtensionString = "jpg,jpeg,jpe,ico,gif,bmp,png")] + public class ImageFile : ImageData + { + /// + /// Gets or sets the copyright. + /// + /// + /// The copyright. + /// + public virtual string Copyright { get; set; } + } +} diff --git a/src/alloy/Models/Media/VideoFile.cs b/src/alloy/Models/Media/VideoFile.cs new file mode 100644 index 0000000..0566d47 --- /dev/null +++ b/src/alloy/Models/Media/VideoFile.cs @@ -0,0 +1,24 @@ +using System.ComponentModel.DataAnnotations; +using EPiServer.Core; +using EPiServer.DataAnnotations; +using EPiServer.Framework.DataAnnotations; +using EPiServer.Web; + +namespace AlloyTemplates.Models.Media +{ + [ContentType(GUID = "85468104-E06F-47E5-A317-FC9B83D3CBA6")] + [MediaDescriptor(ExtensionString = "flv,mp4,webm")] + public class VideoFile : VideoData + { + /// + /// Gets or sets the copyright. + /// + public virtual string Copyright { get; set; } + + /// + /// Gets or sets the URL to the preview image. + /// + [UIHint(UIHint.Image)] + public virtual ContentReference PreviewImage { get; set; } + } +} diff --git a/src/alloy/Models/Pages/ArticlePage.cs b/src/alloy/Models/Pages/ArticlePage.cs new file mode 100644 index 0000000..9d1039e --- /dev/null +++ b/src/alloy/Models/Pages/ArticlePage.cs @@ -0,0 +1,14 @@ +namespace AlloyTemplates.Models.Pages +{ + /// + /// Used primarily for publishing news articles on the website + /// + [SiteContentType( + GroupName = Global.GroupNames.News, + GUID = "AEECADF2-3E89-4117-ADEB-F8D43565D2F4")] + [SiteImageUrl(Global.StaticGraphicsFolderPath + "page-type-thumbnail-article.png")] + public class ArticlePage : StandardPage + { + + } +} diff --git a/src/alloy/Models/Pages/ContactPage.cs b/src/alloy/Models/Pages/ContactPage.cs new file mode 100644 index 0000000..2d4a682 --- /dev/null +++ b/src/alloy/Models/Pages/ContactPage.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; +using AlloyTemplates.Business.Rendering; +using EPiServer.Web; +using EPiServer.Core; + +namespace AlloyTemplates.Models.Pages +{ + /// + /// Represents contact details for a contact person + /// + [SiteContentType( + GUID = "F8D47655-7B50-4319-8646-3369BA9AF05B", + GroupName = Global.GroupNames.Specialized)] + [SiteImageUrl(Global.StaticGraphicsFolderPath + "page-type-thumbnail-contact.png")] + public class ContactPage : SitePageData, IContainerPage + { + [Display(GroupName = Global.GroupNames.Contact)] + [UIHint(UIHint.Image)] + public virtual ContentReference Image { get; set; } + + [Display(GroupName = Global.GroupNames.Contact)] + public virtual string Phone { get; set; } + + [Display(GroupName = Global.GroupNames.Contact)] + [EmailAddress] + public virtual string Email { get; set; } + } +} diff --git a/src/alloy/Models/Pages/ContainerPage.cs b/src/alloy/Models/Pages/ContainerPage.cs new file mode 100644 index 0000000..21e664b --- /dev/null +++ b/src/alloy/Models/Pages/ContainerPage.cs @@ -0,0 +1,16 @@ +using AlloyTemplates.Business.Rendering; + +namespace AlloyTemplates.Models.Pages +{ + /// + /// Used to logically group pages in the page tree + /// + [SiteContentType( + GUID = "D178950C-D20E-4A46-90BD-5338B2424745", + GroupName = Global.GroupNames.Specialized)] + [SiteImageUrl] + public class ContainerPage : SitePageData, IContainerPage + { + + } +} diff --git a/src/alloy/Models/Pages/IHasRelatedContent.cs b/src/alloy/Models/Pages/IHasRelatedContent.cs new file mode 100644 index 0000000..a95bd0b --- /dev/null +++ b/src/alloy/Models/Pages/IHasRelatedContent.cs @@ -0,0 +1,9 @@ +using EPiServer.Core; + +namespace AlloyTemplates.Models.Pages +{ + public interface IHasRelatedContent + { + ContentArea RelatedContentArea { get; } + } +} diff --git a/src/alloy/Models/Pages/ISearchPage.cs b/src/alloy/Models/Pages/ISearchPage.cs new file mode 100644 index 0000000..4baa790 --- /dev/null +++ b/src/alloy/Models/Pages/ISearchPage.cs @@ -0,0 +1,9 @@ +namespace AlloyTemplates.Models.Pages +{ + /// + /// Marker interface for search implementation + /// + public interface ISearchPage + { + } +} diff --git a/src/alloy/Models/Pages/LandingPage.cs b/src/alloy/Models/Pages/LandingPage.cs new file mode 100644 index 0000000..d6f99cd --- /dev/null +++ b/src/alloy/Models/Pages/LandingPage.cs @@ -0,0 +1,31 @@ +using System.ComponentModel.DataAnnotations; +using EPiServer.Core; +using EPiServer.DataAbstraction; +using EPiServer.DataAnnotations; + +namespace AlloyTemplates.Models.Pages +{ + /// + /// Used for campaign or landing pages, commonly used for pages linked in online advertising such as AdWords + /// + [SiteContentType( + GUID = "DBED4258-8213-48DB-A11F-99C034172A54", + GroupName = Global.GroupNames.Specialized)] + [SiteImageUrl] + public class LandingPage : SitePageData + { + [Display( + GroupName = SystemTabNames.Content, + Order=310)] + [CultureSpecific] + public virtual ContentArea MainContentArea { get; set; } + + public override void SetDefaultValues(ContentType contentType) + { + base.SetDefaultValues(contentType); + + HideSiteFooter = true; + HideSiteHeader = true; + } + } +} diff --git a/src/alloy/Models/Pages/NewsPage.cs b/src/alloy/Models/Pages/NewsPage.cs new file mode 100644 index 0000000..0f00282 --- /dev/null +++ b/src/alloy/Models/Pages/NewsPage.cs @@ -0,0 +1,36 @@ +using System.ComponentModel.DataAnnotations; +using EPiServer.DataAbstraction; +using EPiServer.Filters; +using EPiServer.Framework.Localization; +using EPiServer.ServiceLocation; +using AlloyTemplates.Business; +using AlloyTemplates.Models.Blocks; + +namespace AlloyTemplates.Models.Pages +{ + /// + /// Presents a news section including a list of the most recent articles on the site + /// + [SiteContentType(GUID = "638D8271-5CA3-4C72-BABC-3E8779233263")] + [SiteImageUrl] + public class NewsPage : StandardPage + { + [Display( + GroupName = SystemTabNames.Content, + Order = 305)] + public virtual PageListBlock NewsList { get; set; } + + public override void SetDefaultValues(ContentType contentType) + { + base.SetDefaultValues(contentType); + + NewsList.Count = 20; + NewsList.Heading = ServiceLocator.Current.GetInstance().GetString("/newspagetemplate/latestnews"); + NewsList.IncludeIntroduction = true; + NewsList.IncludePublishDate = true; + NewsList.Recursive = true; + NewsList.PageTypeFilter = typeof(ArticlePage).GetPageType(); + NewsList.SortOrder = FilterSortOrder.PublishedDescending; + } + } +} diff --git a/src/alloy/Models/Pages/ProductPage.cs b/src/alloy/Models/Pages/ProductPage.cs new file mode 100644 index 0000000..7b1140b --- /dev/null +++ b/src/alloy/Models/Pages/ProductPage.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using AlloyTemplates.Models.Blocks; +using EPiServer.Core; +using EPiServer.DataAbstraction; +using EPiServer.DataAnnotations; +using AlloyTemplates.Models.Properties; + +namespace AlloyTemplates.Models.Pages +{ + /// + /// Used to present a single product + /// + [SiteContentType( + GUID = "17583DCD-3C11-49DD-A66D-0DEF0DD601FC", + GroupName = Global.GroupNames.Products)] + [SiteImageUrl(Global.StaticGraphicsFolderPath + "page-type-thumbnail-product.png")] + [AvailableContentTypes( + Availability = Availability.Specific, + IncludeOn = new[] { typeof(StartPage) })] + public class ProductPage : StandardPage, IHasRelatedContent + { + [Required] + [Display(Order = 305)] + [UIHint(Global.SiteUIHints.StringsCollection)] + [CultureSpecific] + public virtual IList UniqueSellingPoints { get; set; } + + [Display( + GroupName = SystemTabNames.Content, + Order = 330)] + [CultureSpecific] + [AllowedTypes(new[] { typeof(IContentData) },new[] { typeof(JumbotronBlock) })] + public virtual ContentArea RelatedContentArea { get; set; } + } +} diff --git a/src/alloy/Models/Pages/SearchPage.cs b/src/alloy/Models/Pages/SearchPage.cs new file mode 100644 index 0000000..aae40ea --- /dev/null +++ b/src/alloy/Models/Pages/SearchPage.cs @@ -0,0 +1,25 @@ +using System.ComponentModel.DataAnnotations; +using AlloyTemplates.Models.Blocks; +using EPiServer.Core; +using EPiServer.DataAbstraction; +using EPiServer.DataAnnotations; + +namespace AlloyTemplates.Models.Pages +{ + /// + /// Used to provide on-site search + /// + [SiteContentType( + GUID = "AAC25733-1D21-4F82-B031-11E626C91E30", + GroupName = Global.GroupNames.Specialized)] + [SiteImageUrl] + public class SearchPage : SitePageData, IHasRelatedContent, ISearchPage + { + [Display( + GroupName = SystemTabNames.Content, + Order = 310)] + [CultureSpecific] + [AllowedTypes(new[] { typeof(IContentData) }, new[] { typeof(JumbotronBlock) })] + public virtual ContentArea RelatedContentArea { get; set; } + } +} diff --git a/src/alloy/Models/Pages/SitePageData.cs b/src/alloy/Models/Pages/SitePageData.cs new file mode 100644 index 0000000..accd83f --- /dev/null +++ b/src/alloy/Models/Pages/SitePageData.cs @@ -0,0 +1,96 @@ +using System.ComponentModel.DataAnnotations; +using EPiServer.Core; +using EPiServer.DataAbstraction; +using EPiServer.DataAnnotations; +using AlloyTemplates.Business.Rendering; +using AlloyTemplates.Models.Properties; +using EPiServer.Web; + +namespace AlloyTemplates.Models.Pages +{ + /// + /// Base class for all page types + /// + public abstract class SitePageData : PageData, ICustomCssInContentArea + { + [Display( + GroupName = Global.GroupNames.MetaData, + Order = 100)] + [CultureSpecific] + public virtual string MetaTitle + { + get + { + var metaTitle = this.GetPropertyValue(p => p.MetaTitle); + + // Use explicitly set meta title, otherwise fall back to page name + return !string.IsNullOrWhiteSpace(metaTitle) + ? metaTitle + : PageName; + } + set { this.SetPropertyValue(p => p.MetaTitle, value); } + } + + [Display( + GroupName = Global.GroupNames.MetaData, + Order = 200)] + [CultureSpecific] + [BackingType(typeof(PropertyStringList))] + public virtual string[] MetaKeywords { get; set; } + + [Display( + GroupName = Global.GroupNames.MetaData, + Order = 300)] + [CultureSpecific] + [UIHint(UIHint.Textarea)] + public virtual string MetaDescription { get; set; } + + [Display( + GroupName = Global.GroupNames.MetaData, + Order = 400)] + [CultureSpecific] + public virtual bool DisableIndexing { get; set; } + + [Display( + GroupName = SystemTabNames.Content, + Order = 100)] + [UIHint(UIHint.Image)] + public virtual ContentReference PageImage { get; set; } + + [Display( + GroupName = SystemTabNames.Content, + Order = 200)] + [CultureSpecific] + [UIHint(UIHint.Textarea)] + public virtual string TeaserText + { + get + { + var teaserText = this.GetPropertyValue(p => p.TeaserText); + + // Use explicitly set teaser text, otherwise fall back to description + return !string.IsNullOrWhiteSpace(teaserText) + ? teaserText + : MetaDescription; + } + set { this.SetPropertyValue(p => p.TeaserText, value); } + } + + [Display( + GroupName = SystemTabNames.Settings, + Order = 200)] + [CultureSpecific] + public virtual bool HideSiteHeader { get; set; } + + [Display( + GroupName = SystemTabNames.Settings, + Order = 300)] + [CultureSpecific] + public virtual bool HideSiteFooter { get; set; } + + public string ContentAreaCssClass + { + get { return "teaserblock"; } //Page partials should be style like teasers + } + } +} diff --git a/src/alloy/Models/Pages/StandardPage.cs b/src/alloy/Models/Pages/StandardPage.cs new file mode 100644 index 0000000..cd5b8c5 --- /dev/null +++ b/src/alloy/Models/Pages/StandardPage.cs @@ -0,0 +1,26 @@ +using EPiServer.Core; +using EPiServer.DataAbstraction; +using EPiServer.DataAnnotations; +using System.ComponentModel.DataAnnotations; + +namespace AlloyTemplates.Models.Pages +{ + /// + /// Used for the pages mainly consisting of manually created content such as text, images, and blocks + /// + [SiteContentType(GUID = "9CCC8A41-5C8C-4BE0-8E73-520FF3DE8267")] + [SiteImageUrl(Global.StaticGraphicsFolderPath + "page-type-thumbnail-standard.png")] + public class StandardPage : SitePageData + { + [Display( + GroupName = SystemTabNames.Content, + Order = 310)] + [CultureSpecific] + public virtual XhtmlString MainBody { get; set; } + + [Display( + GroupName = SystemTabNames.Content, + Order = 320)] + public virtual ContentArea MainContentArea { get; set; } + } +} diff --git a/src/alloy/Models/Pages/StartPage.cs b/src/alloy/Models/Pages/StartPage.cs new file mode 100644 index 0000000..42544a5 --- /dev/null +++ b/src/alloy/Models/Pages/StartPage.cs @@ -0,0 +1,54 @@ +using System.ComponentModel.DataAnnotations; +using EPiServer.Core; +using EPiServer.DataAbstraction; +using EPiServer.DataAnnotations; +using EPiServer.SpecializedProperties; +using AlloyTemplates.Models.Blocks; + +namespace AlloyTemplates.Models.Pages +{ + /// + /// Used for the site's start page and also acts as a container for site settings + /// + [ContentType( + GUID = "19671657-B684-4D95-A61F-8DD4FE60D559", + GroupName = Global.GroupNames.Specialized)] + [SiteImageUrl] + [AvailableContentTypes( + Availability.Specific, + Include = new[] { typeof(ContainerPage), typeof(ProductPage), typeof(StandardPage), typeof(ISearchPage), typeof(LandingPage), typeof(ContentFolder) }, // Pages we can create under the start page... + ExcludeOn = new[] { typeof(ContainerPage), typeof(ProductPage), typeof(StandardPage), typeof(ISearchPage), typeof(LandingPage) })] // ...and underneath those we can't create additional start pages + public class StartPage : SitePageData + { + [Display( + GroupName = SystemTabNames.Content, + Order = 320)] + [CultureSpecific] + public virtual ContentArea MainContentArea { get; set; } + + [Display(GroupName = Global.GroupNames.SiteSettings, Order = 300)] + public virtual LinkItemCollection ProductPageLinks { get; set; } + + [Display(GroupName = Global.GroupNames.SiteSettings, Order = 350)] + public virtual LinkItemCollection CompanyInformationPageLinks { get; set; } + + [Display(GroupName = Global.GroupNames.SiteSettings, Order = 400)] + public virtual LinkItemCollection NewsPageLinks { get; set; } + + [Display(GroupName = Global.GroupNames.SiteSettings, Order = 450)] + public virtual LinkItemCollection CustomerZonePageLinks { get; set; } + + [Display(GroupName = Global.GroupNames.SiteSettings)] + public virtual PageReference GlobalNewsPageLink { get; set; } + + [Display(GroupName = Global.GroupNames.SiteSettings)] + public virtual PageReference ContactsPageLink { get; set; } + + [Display(GroupName = Global.GroupNames.SiteSettings)] + public virtual PageReference SearchPageLink { get; set; } + + [Display(GroupName = Global.GroupNames.SiteSettings)] + public virtual SiteLogotypeBlock SiteLogotype { get; set; } + + } +} diff --git a/src/alloy/Models/Pages/TestPage.cs b/src/alloy/Models/Pages/TestPage.cs new file mode 100644 index 0000000..3587cd1 --- /dev/null +++ b/src/alloy/Models/Pages/TestPage.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; +using EPiServer.DataAbstraction; +using EPiServer.DataAnnotations; + +namespace AlloyTemplates.Models.Pages +{ + [ContentType(GUID = "DA06F097-5C32-4C9A-8A4F-22D43F9E8B5A", GroupName = Global.GroupNames.Specialized)] + public class TestPage : SitePageData + { + [Display(GroupName = SystemTabNames.Content, Order = 320)] + public virtual string Text1 { get; set; } + } +} diff --git a/src/alloy/Models/Pages/_ReadMe.txt b/src/alloy/Models/Pages/_ReadMe.txt new file mode 100644 index 0000000..f0ca451 --- /dev/null +++ b/src/alloy/Models/Pages/_ReadMe.txt @@ -0,0 +1,6 @@ +This folder contains all page types. + +Blocks should be named with a suffix of "Page", such as "StandardPage" or "ProductPage". + +Default page templates should be named with a suffix of "Template", +such as "StandardPageTemplate" or "ProductPageTemplate". diff --git a/src/alloy/Models/Properties/PropertyStringList.cs b/src/alloy/Models/Properties/PropertyStringList.cs new file mode 100644 index 0000000..1ca58c5 --- /dev/null +++ b/src/alloy/Models/Properties/PropertyStringList.cs @@ -0,0 +1,67 @@ +using System; +using EPiServer.Core; +using EPiServer.Framework.DataAnnotations; +using EPiServer.PlugIn; + +namespace AlloyTemplates.Models.Properties +{ + /// + /// Property type for storing a list of strings + /// + /// For an example, see where this property type is used for the MetaKeywords property + [EditorHint(Global.SiteUIHints.Strings)] + [PropertyDefinitionTypePlugIn(Description = "A property for list of strings", DisplayName = "String List")] + public class PropertyStringList : PropertyLongString + { + protected String Separator = "\n"; + + public String[] List + { + get + { + return (String[])Value; + } + } + + public override Type PropertyValueType + { + get + { + return typeof(String[]); + } + } + + public override object SaveData(PropertyDataCollection properties) + { + return LongString; + } + + public override object Value + { + get + { + var value = base.Value as string; + + if (value == null) + { + return null; + } + + return value.Split(Separator.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); + } + set + { + if (value is String[]) + { + var s = String.Join(Separator, value as String[]); + base.Value = s; + } + else + { + base.Value = value; + } + + } + } + } +} diff --git a/src/alloy/Models/Register/RegisterViewModel.cs b/src/alloy/Models/Register/RegisterViewModel.cs new file mode 100644 index 0000000..6cf7ba9 --- /dev/null +++ b/src/alloy/Models/Register/RegisterViewModel.cs @@ -0,0 +1,33 @@ +using System.ComponentModel.DataAnnotations; +using System.Web.Mvc; + +namespace AlloyTemplates.Models +{ + public class RegisterViewModel + { + [Required] + [Display(Name = "Username")] + [RegularExpression(@"^[a-zA-Z0-9_-]+$", ErrorMessage = "Username can only contain letters a-z, numbers, underscores and hyphens.")] + [StringLength(20, ErrorMessage ="The {0} field can not be more than {1} characters long.")] + public string Username { get; set; } + + [Required] + [EmailAddress] + [Display(Name = "Email")] + 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")] + [AllowHtml] + public string Password { get; set; } + + [DataType(DataType.Password)] + [Display(Name = "Confirm password")] + [System.ComponentModel.DataAnnotations.Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] + [AllowHtml] + public string ConfirmPassword { get; set; } + + } +} diff --git a/src/alloy/Models/SiteContentType.cs b/src/alloy/Models/SiteContentType.cs new file mode 100644 index 0000000..a5676cf --- /dev/null +++ b/src/alloy/Models/SiteContentType.cs @@ -0,0 +1,15 @@ +using EPiServer.DataAnnotations; + +namespace AlloyTemplates.Models +{ + /// + /// Attribute used for site content types to set default attribute values + /// + public class SiteContentType : ContentTypeAttribute + { + public SiteContentType() + { + GroupName = Global.GroupNames.Default; + } + } +} diff --git a/src/alloy/Models/SiteImageUrl.cs b/src/alloy/Models/SiteImageUrl.cs new file mode 100644 index 0000000..e3cb468 --- /dev/null +++ b/src/alloy/Models/SiteImageUrl.cs @@ -0,0 +1,23 @@ +using EPiServer.DataAnnotations; + +namespace AlloyTemplates.Models +{ + /// + /// Attribute to set the default thumbnail for site page and block types + /// + public class SiteImageUrl : ImageUrlAttribute + { + /// + /// The parameterless constructor will initialize a SiteImageUrl attribute with a default thumbnail + /// + public SiteImageUrl() : base("~/Static/gfx/page-type-thumbnail.png") + { + + } + + public SiteImageUrl(string path) : base(path) + { + + } + } +} diff --git a/src/alloy/Models/ViewModels/ContactBlockModel.cs b/src/alloy/Models/ViewModels/ContactBlockModel.cs new file mode 100644 index 0000000..260e386 --- /dev/null +++ b/src/alloy/Models/ViewModels/ContactBlockModel.cs @@ -0,0 +1,19 @@ +using System.Web; +using System.ComponentModel.DataAnnotations; +using AlloyTemplates.Models.Pages; +using EPiServer.Web; +using EPiServer.Core; + +namespace AlloyTemplates.Models.ViewModels +{ + public class ContactBlockModel + { + [UIHint(UIHint.Image)] + public ContentReference Image { get; set; } + public string Heading { get; set; } + public string LinkText { get; set; } + public IHtmlString LinkUrl { get; set; } + public bool ShowLink { get; set; } + public ContactPage ContactPage { get; set; } + } +} diff --git a/src/alloy/Models/ViewModels/ContentRenderingErrorModel.cs b/src/alloy/Models/ViewModels/ContentRenderingErrorModel.cs new file mode 100644 index 0000000..cbf8a68 --- /dev/null +++ b/src/alloy/Models/ViewModels/ContentRenderingErrorModel.cs @@ -0,0 +1,30 @@ +using System; +using EPiServer; +using EPiServer.Core; + +namespace AlloyTemplates.Models.ViewModels +{ + public class ContentRenderingErrorModel + { + public ContentRenderingErrorModel(IContentData contentData, Exception exception) + { + var content = contentData as IContent; + if(content != null) + { + ContentName = content.Name; + } + else + { + ContentName = string.Empty; + } + + ContentTypeName = contentData.GetOriginalType().Name; + + Exception = exception; + } + + public string ContentName { get; set; } + public string ContentTypeName { get; set; } + public Exception Exception { get; set; } + } +} diff --git a/src/alloy/Models/ViewModels/IPageViewModel.cs b/src/alloy/Models/ViewModels/IPageViewModel.cs new file mode 100644 index 0000000..ca9160e --- /dev/null +++ b/src/alloy/Models/ViewModels/IPageViewModel.cs @@ -0,0 +1,19 @@ +using EPiServer.Core; +using AlloyTemplates.Models.Pages; + +namespace AlloyTemplates.Models.ViewModels +{ + /// + /// Defines common characteristics for view models for pages, including properties used by layout files. + /// + /// + /// Views which should handle several page types (T) can use this interface as model type rather than the + /// concrete PageViewModel class, utilizing the that this interface is covariant. + /// + public interface IPageViewModel where T : SitePageData + { + T CurrentPage { get; } + LayoutModel Layout { get; set; } + IContent Section { get; set; } + } +} diff --git a/src/alloy/Models/ViewModels/ImageViewModel.cs b/src/alloy/Models/ViewModels/ImageViewModel.cs new file mode 100644 index 0000000..068396d --- /dev/null +++ b/src/alloy/Models/ViewModels/ImageViewModel.cs @@ -0,0 +1,24 @@ + +namespace AlloyTemplates.Models.ViewModels +{ + /// + /// View model for the image file + /// + public class ImageViewModel + { + /// + /// Gets or sets the URL to the image. + /// + public string Url { get; set; } + + /// + /// Gets or sets the name of the image. + /// + public string Name { get; set; } + + /// + /// Gets or sets the copyright information of the image. + /// + public string Copyright { get; set; } + } +} diff --git a/src/alloy/Models/ViewModels/LayoutModel.cs b/src/alloy/Models/ViewModels/LayoutModel.cs new file mode 100644 index 0000000..ebba574 --- /dev/null +++ b/src/alloy/Models/ViewModels/LayoutModel.cs @@ -0,0 +1,25 @@ +using System.Web; +using System.Web.Mvc; +using EPiServer.SpecializedProperties; +using AlloyTemplates.Models.Blocks; + +namespace AlloyTemplates.Models.ViewModels +{ + public class LayoutModel + { + public SiteLogotypeBlock Logotype { get; set; } + public IHtmlString LogotypeLinkUrl { get; set; } + public bool HideHeader { get; set; } + public bool HideFooter { get; set; } + public LinkItemCollection ProductPages { get; set; } + public LinkItemCollection CompanyInformationPages { get; set; } + public LinkItemCollection NewsPages { get; set; } + public LinkItemCollection CustomerZonePages { get; set; } + public bool LoggedIn { get; set; } + public MvcHtmlString LoginUrl { get; set; } + public MvcHtmlString LogOutUrl { get; set; } + public MvcHtmlString SearchActionUrl { get; set; } + + public bool IsInReadonlyMode {get;set;} + } +} diff --git a/src/alloy/Models/ViewModels/PageListModel.cs b/src/alloy/Models/ViewModels/PageListModel.cs new file mode 100644 index 0000000..01238c3 --- /dev/null +++ b/src/alloy/Models/ViewModels/PageListModel.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using EPiServer.Core; +using AlloyTemplates.Models.Blocks; + +namespace AlloyTemplates.Models.ViewModels +{ + public class PageListModel + { + public PageListModel(PageListBlock block) + { + Heading = block.Heading; + ShowIntroduction = block.IncludeIntroduction; + ShowPublishDate = block.IncludePublishDate; + } + public string Heading { get; set; } + public IEnumerable Pages { get; set; } + public bool ShowIntroduction { get; set; } + public bool ShowPublishDate { get; set; } + } +} diff --git a/src/alloy/Models/ViewModels/PageViewModel.cs b/src/alloy/Models/ViewModels/PageViewModel.cs new file mode 100644 index 0000000..712c239 --- /dev/null +++ b/src/alloy/Models/ViewModels/PageViewModel.cs @@ -0,0 +1,32 @@ +using System; +using EPiServer.Core; +using AlloyTemplates.Models.Pages; + +namespace AlloyTemplates.Models.ViewModels +{ + public class PageViewModel : IPageViewModel where T : SitePageData + { + public PageViewModel(T currentPage) + { + CurrentPage = currentPage; + } + + public T CurrentPage { get; private set; } + public LayoutModel Layout { get; set; } + public IContent Section { get; set; } + } + + public static class PageViewModel + { + /// + /// Returns a PageViewModel of type . + /// + /// + /// Convenience method for creating PageViewModels without having to specify the type as methods can use type inference while constructors cannot. + /// + public static PageViewModel Create(T page) where T : SitePageData + { + return new PageViewModel(page); + } + } +} diff --git a/src/alloy/Models/ViewModels/PreviewModel.cs b/src/alloy/Models/ViewModels/PreviewModel.cs new file mode 100644 index 0000000..b14d72f --- /dev/null +++ b/src/alloy/Models/ViewModels/PreviewModel.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using EPiServer.Core; +using AlloyTemplates.Models.Pages; + +namespace AlloyTemplates.Models.ViewModels +{ + public class PreviewModel : PageViewModel + { + public PreviewModel(SitePageData currentPage, IContent previewContent) + : base(currentPage) + { + PreviewContent = previewContent; + Areas = new List(); + } + + public IContent PreviewContent { get; set; } + public List Areas { get; set; } + + public class PreviewArea + { + public bool Supported { get; set; } + public string AreaName { get; set; } + public string AreaTag { get; set; } + public ContentArea ContentArea { get; set; } + } + } +} diff --git a/src/alloy/Models/ViewModels/SearchContentModel.cs b/src/alloy/Models/ViewModels/SearchContentModel.cs new file mode 100644 index 0000000..4540921 --- /dev/null +++ b/src/alloy/Models/ViewModels/SearchContentModel.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using AlloyTemplates.Models.Pages; + +namespace AlloyTemplates.Models.ViewModels +{ + public class SearchContentModel : PageViewModel + { + public SearchContentModel(SearchPage currentPage) : base(currentPage) + { + } + + public bool SearchServiceDisabled { get; set; } + public string SearchedQuery { get; set; } + public int NumberOfHits { get; set; } + public IEnumerable Hits { get; set; } + + public class SearchHit + { + public string Title { get; set; } + public string Url { get; set; } + public string Excerpt { get; set; } + } + } +} diff --git a/src/alloy/Models/ViewModels/VideoViewModel.cs b/src/alloy/Models/ViewModels/VideoViewModel.cs new file mode 100644 index 0000000..a2bca6d --- /dev/null +++ b/src/alloy/Models/ViewModels/VideoViewModel.cs @@ -0,0 +1,19 @@ + +namespace AlloyTemplates.Models.ViewModels +{ + /// + /// View model for the video file + /// + public class VideoViewModel + { + /// + /// Gets or sets the URL to the video. + /// + public string Url { get; set; } + + /// + /// Gets or sets the URL to a preview image for the video. + /// + public string PreviewImageUrl { get; set; } + } +} diff --git a/src/alloy/Properties/AssemblyInfo.cs b/src/alloy/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..dd08417 --- /dev/null +++ b/src/alloy/Properties/AssemblyInfo.cs @@ -0,0 +1,28 @@ +using System; +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("EPiServer CMS MVC Template package")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyProduct("EPiServer CMS MVC Template package")] + +[assembly: AssemblyCompany("EPiServer AB")] +[assembly: AssemblyCopyright("© 2003-2017 by EPiServer AB. All rights reserved")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: AssemblyConfiguration("")] + + +// 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)] + + +[assembly: CLSCompliant(false)] +[assembly: AssemblyVersion("1.2.0")] +[assembly: AssemblyInformationalVersion("1.2.0-developerbuild")] diff --git a/src/alloy/Resources/LanguageFiles/ContentTypeNames.xml b/src/alloy/Resources/LanguageFiles/ContentTypeNames.xml new file mode 100644 index 0000000..d017d92 --- /dev/null +++ b/src/alloy/Resources/LanguageFiles/ContentTypeNames.xml @@ -0,0 +1,87 @@ + + + + + + Page List + Displays a list of pages, for example to display recent news + + + Teaser + Used to insert a content teaser + + + Logotype + Used to set the logotype for the website + + + Video Player + Used to embed a video player + + + Editorial + Used to add simple editorial content + + + Contact + Used to add contact information + + + Button + Used to add a button with a link + + + Jumbotron + Used to add a large section + + + Article + Used to publish news articles on the website + + + Contact + Used to publish contact details for a specific contact + + + Container Page + Used to logically group pages in the content tree + + + Landing Page + Used to create a page consisting entirely of blocks + + + News Page + Used as a start page for a site's news section and commonly displays a list of the most recent articles + + + Product + Used to present a specific product + + + Search Page + Used to provide on-site search features + + + Start Page + The home page of the website + + + Standard Page + Used mainly for default editorial content such as text and images + + + Image + Used for image files (BMP, GIF, ICO, JPEG, PNG) + + + Video + Used for video files (FLV, MP4, WEBM) + + + Generic File + Used for media which doesn't have a specific content type + + + + diff --git a/src/alloy/Resources/LanguageFiles/Display.xml b/src/alloy/Resources/LanguageFiles/Display.xml new file mode 100644 index 0000000..8d0936c --- /dev/null +++ b/src/alloy/Resources/LanguageFiles/Display.xml @@ -0,0 +1,24 @@ + + + + + + Mobile + + + Web + + + + Full + Wide + Narrow + + + Standard (1366x768) + iPad horizontal (1024x768) + iPhone vertical (320x568) + Android vertical (480x800) + + + \ No newline at end of file diff --git a/src/alloy/Resources/LanguageFiles/EditorHints.xml b/src/alloy/Resources/LanguageFiles/EditorHints.xml new file mode 100644 index 0000000..895e0dd --- /dev/null +++ b/src/alloy/Resources/LanguageFiles/EditorHints.xml @@ -0,0 +1,32 @@ + + + + + + + + + + Button Text + + + + + + This block type does not have a renderer for this type of content area. + + + + + + Error while rendering {0} {1} + + + + The block '{0}' when displayed as {1} + The block '{0}' cannot be displayed as {1} + No renderer found for '{0}' + + + + diff --git a/src/alloy/Resources/LanguageFiles/GroupNames.xml b/src/alloy/Resources/LanguageFiles/GroupNames.xml new file mode 100644 index 0000000..baee814 --- /dev/null +++ b/src/alloy/Resources/LanguageFiles/GroupNames.xml @@ -0,0 +1,29 @@ + + + + + + + + Default + + + News + + + Products + + + SEO + + + Site settings + + + Specialized + + + + + + diff --git a/src/alloy/Resources/LanguageFiles/PropertyNames.xml b/src/alloy/Resources/LanguageFiles/PropertyNames.xml new file mode 100644 index 0000000..f5093b8 --- /dev/null +++ b/src/alloy/Resources/LanguageFiles/PropertyNames.xml @@ -0,0 +1,220 @@ + + + + + + + + + Disable indexing + Prevents the page from being indexed by search engines + + + Page description + Used as the meta description and commonly as an ingress + + + Keywords + + + Title + + + Teaser text + Can be used to display a text other than the description when the page is dropped in a content area + + + Teaser image + An image used in different contexts, for example when the page is dropped in a content area + + + Hide site header + Check this setting to hide the header including the main navigation + + + Hide site footer + Check this setting to hide the footer + + + + Main body + Main editorial content of the page + + + Large content area + + + + + + + + Unique selling points + + + Small content area + + + + + + + + Products + + + Company information + + + Customer zone + + + Local news + + + Global news + + + Contact pages + + + First content area + + + Second content area + + + Logotype + + + Search page + + + + + + + + Image + + + Heading + + + Contact + Select who you want to show contact details for + + + Link text + + + Link + + + + + + + + Heading + + + Include publish date + + + Include description + + + Sort order + + + Max count + + + Page list root + + + Include all levels + + + Filter by page type + + + Category filter + If set, only pages matching at least one of the specified categories will be included in the list + + + + + + + + Image + + + Image description + + + Large heading + + + Small heading + + + Button text + + + Button link + + + + + + + + Heading + + + Text + + + Image + + + Link + + + + + + + + Logotype + + + <caption>Title</caption> + + + + + + + + Copyright + + + + + + + + Copyright + + + Preview image + + + + + + diff --git a/src/alloy/Resources/LanguageFiles/PropertyNames_sv.xml b/src/alloy/Resources/LanguageFiles/PropertyNames_sv.xml new file mode 100644 index 0000000..19ff33e --- /dev/null +++ b/src/alloy/Resources/LanguageFiles/PropertyNames_sv.xml @@ -0,0 +1,220 @@ + + + + + + + + + Disable indexing + Prevents the page from being indexed by search engines + + + Page description + Used as the meta description and commonly as an ingress + + + Keywords + + + Title + + + Teaser text + Can be used to display a text other than the description when the page is dropped in a content area + + + Teaser image + An image used in different contexts, for example when the page is dropped in a content area + + + Hide site header + Check this setting to hide the header including the main navigation + + + Hide site footer + Check this setting to hide the footer + + + + Main body + Main editorial content of the page + + + Large content area + + + + + + + + Unique selling points + + + Small content area + + + + + + + + Products + + + Company information + + + Customer zone + + + Local news + + + Global news + + + Contact pages + + + First content area + + + Second content area + + + Logotype + + + Search page + + + + + + + + Image + + + Heading + + + Contact + Select who you want to show contact details for + + + Link text + + + Link + + + + + + + + Heading + + + Include publish date + + + Include description + + + Sort order + + + Max count + + + Page list root + + + Include all levels + + + Filter by page type + + + Category filter + If set, only pages matching at least one of the specified categories will be included in the list + + + + + + + + Image + + + Image description + + + Large heading + + + Small heading + + + Button text + + + Button link + + + + + + + + Heading + + + Text + + + Image + + + Link + + + + + + + + Logotype + + + <caption>Title</caption> + + + + + + + + Copyright + + + + + + + + Copyright + + + Preview image + + + + + + diff --git a/src/alloy/Resources/LanguageFiles/Views.xml b/src/alloy/Resources/LanguageFiles/Views.xml new file mode 100644 index 0000000..b6f97b2 --- /dev/null +++ b/src/alloy/Resources/LanguageFiles/Views.xml @@ -0,0 +1,42 @@ + + + + + + + E-mail + Phone + No contact selected + + +
+ The Company + Customer Zone + Log in + Log out + News & Events + Products +
+ + + Search + + + + Latest news + News list will be empty since no list root has been set + + + + no + Search result + Search + Your search for + resulted in + hits + EPiServer Search is not configured or is not active for this website. + + +
+ +
diff --git a/src/alloy/Resources/LanguageFiles/_ReadMe.txt b/src/alloy/Resources/LanguageFiles/_ReadMe.txt new file mode 100644 index 0000000..98c4d84 --- /dev/null +++ b/src/alloy/Resources/LanguageFiles/_ReadMe.txt @@ -0,0 +1,11 @@ +All language files in this folder are included in the LocalizationService. + +The path to this folder is configured in EPiServerFramework.config: + + + + + + diff --git a/src/alloy/Startup.cs b/src/alloy/Startup.cs new file mode 100644 index 0000000..6148c99 --- /dev/null +++ b/src/alloy/Startup.cs @@ -0,0 +1,48 @@ +using System; +using System.Web; +using EPiServer.Cms.UI.AspNetIdentity; +using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.Owin; +using Microsoft.Owin; +using Microsoft.Owin.Security.Cookies; +using Owin; + +[assembly: OwinStartup(typeof(AlloyTemplates.Startup))] + +namespace AlloyTemplates +{ + public class Startup + { + + public void Configuration(IAppBuilder app) + { + + // Add CMS integration for ASP.NET Identity + app.AddCmsAspNetIdentity(); + + // Remove to block registration of administrators + app.UseAdministratorRegistrationPage(() => HttpContext.Current.Request.IsLocal); + + // Use cookie authentication + app.UseCookieAuthentication(new CookieAuthenticationOptions + { + AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, + LoginPath = new PathString(Global.LoginPath), + Provider = new CookieAuthenticationProvider + { + // If the "/util/login.aspx" has been used for login otherwise you don't need it you can remove OnApplyRedirect. + OnApplyRedirect = cookieApplyRedirectContext => + { + app.CmsOnCookieApplyRedirect(cookieApplyRedirectContext, cookieApplyRedirectContext.OwinContext.Get>()); + }, + + // Enables the application to validate the security stamp when the user logs in. + // This is a security feature which is used when you change a password or add an external login to your account. + OnValidateIdentity = SecurityStampValidator.OnValidateIdentity, ApplicationUser>( + validateInterval: TimeSpan.FromMinutes(30), + regenerateIdentity: (manager, user) => manager.GenerateUserIdentityAsync(user)) + } + }); + } + } +} diff --git a/src/alloy/Static/css/bootstrap-collapse.js b/src/alloy/Static/css/bootstrap-collapse.js new file mode 100644 index 0000000..d72982e --- /dev/null +++ b/src/alloy/Static/css/bootstrap-collapse.js @@ -0,0 +1,158 @@ +/* ============================================================= + * bootstrap-collapse.js v2.0.4 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* COLLAPSE PUBLIC CLASS DEFINITION + * ================================ */ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options.parent) { + this.$parent = $(this.options.parent) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension + , scroll + , actives + , hasData + + if (this.transitioning) return + + dimension = this.dimension() + scroll = $.camelCase(['scroll', dimension].join('-')) + actives = this.$parent && this.$parent.find('> .accordion-group > .in') + + if (actives && actives.length) { + hasData = actives.data('collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', $.Event('show'), 'shown') + this.$element[dimension](this.$element[0][scroll]) + } + + , hide: function () { + var dimension + if (this.transitioning) return + dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', $.Event('hide'), 'hidden') + this.$element[dimension](0) + } + + , reset: function (size) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') + + return this + } + + , transition: function (method, startEvent, completeEvent) { + var that = this + , complete = function () { + if (startEvent.type == 'show') that.reset() + that.transitioning = 0 + that.$element.trigger(completeEvent) + } + + this.$element.trigger(startEvent) + + if (startEvent.isDefaultPrevented()) return + + this.transitioning = 1 + + this.$element[method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + + /* COLLAPSIBLE PLUGIN DEFINITION + * ============================== */ + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSIBLE DATA-API + * ==================== */ + + + $(function () { + $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $(target).collapse(option) + }) + }) + +}(window.jQuery);// JavaScript Document \ No newline at end of file diff --git a/src/alloy/Static/css/bootstrap-responsive.css b/src/alloy/Static/css/bootstrap-responsive.css new file mode 100644 index 0000000..161270f --- /dev/null +++ b/src/alloy/Static/css/bootstrap-responsive.css @@ -0,0 +1,848 @@ +/*! + * Bootstrap Responsive v2.0.4 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 28px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; +} + +.hidden { + display: none; + visibility: hidden; +} + +.visible-phone { + display: none !important; +} + +.visible-tablet { + display: none !important; +} + +.hidden-desktop { + display: none !important; +} + +@media (max-width: 767px) { + .visible-phone { + display: inherit !important; + } + .hidden-phone { + display: none !important; + } + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important; + } +} + +@media (min-width: 768px) and (max-width: 979px) { + .visible-tablet { + display: inherit !important; + } + .hidden-tablet { + display: none !important; + } + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important ; + } +} + +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[type="checkbox"], + input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-right: 10px; + padding-left: 10px; + } + .modal { + position: absolute; + top: 10px; + right: 10px; + left: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} + +@media (max-width: 767px) { + body { + padding-right: 20px; + padding-left: 20px; + } + .navbar-fixed-top, + .navbar-fixed-bottom { + margin-right: -20px; + margin-left: -20px; + } + .container-fluid { + padding: 0; + } + .dl-horizontal dt { + float: none; + width: auto; + clear: none; + text-align: left; + } + .dl-horizontal dd { + margin-left: 0; + } + .container { + width: auto; + } + .row-fluid { + width: 100%; + } + .row, + .thumbnails { + margin-left: 0; + } + [class*="span"], + .row-fluid [class*="span"] { + display: block; + float: none; + width: auto; + margin-left: 0; + } + .input-large, + .input-xlarge, + .input-xxlarge, + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + } + .input-prepend input, + .input-append input, + .input-prepend input[class*="span"], + .input-append input[class*="span"] { + display: inline-block; + width: auto; + } +} + +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 724px; + } + .span12 { + width: 724px; + } + .span11 { + width: 662px; + } + .span10 { + width: 600px; + } + .span9 { + width: 538px; + } + .span8 { + width: 476px; + } + .span7 { + width: 414px; + } + .span6 { + width: 352px; + } + .span5 { + width: 290px; + } + .span4 { + width: 228px; + } + .span3 { + width: 166px; + } + .span2 { + width: 104px; + } + .span1 { + width: 42px; + } + .offset12 { + margin-left: 764px; + } + .offset11 { + margin-left: 702px; + } + .offset10 { + margin-left: 640px; + } + .offset9 { + margin-left: 578px; + } + .offset8 { + margin-left: 516px; + } + .offset7 { + margin-left: 454px; + } + .offset6 { + margin-left: 392px; + } + .offset5 { + margin-left: 330px; + } + .offset4 { + margin-left: 268px; + } + .offset3 { + margin-left: 206px; + } + .offset2 { + margin-left: 144px; + } + .offset1 { + margin-left: 82px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 28px; + margin-left: 2.762430939%; + *margin-left: 2.709239449638298%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .span12 { + width: 99.999999993%; + *width: 99.9468085036383%; + } + .row-fluid .span11 { + width: 91.436464082%; + *width: 91.38327259263829%; + } + .row-fluid .span10 { + width: 82.87292817100001%; + *width: 82.8197366816383%; + } + .row-fluid .span9 { + width: 74.30939226%; + *width: 74.25620077063829%; + } + .row-fluid .span8 { + width: 65.74585634900001%; + *width: 65.6926648596383%; + } + .row-fluid .span7 { + width: 57.182320438000005%; + *width: 57.129128948638304%; + } + .row-fluid .span6 { + width: 48.618784527%; + *width: 48.5655930376383%; + } + .row-fluid .span5 { + width: 40.055248616%; + *width: 40.0020571266383%; + } + .row-fluid .span4 { + width: 31.491712705%; + *width: 31.4385212156383%; + } + .row-fluid .span3 { + width: 22.928176794%; + *width: 22.874985304638297%; + } + .row-fluid .span2 { + width: 14.364640883%; + *width: 14.311449393638298%; + } + .row-fluid .span1 { + width: 5.801104972%; + *width: 5.747913482638298%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 714px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 652px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 590px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 528px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 466px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 404px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 342px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 280px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 218px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 156px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 94px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 32px; + } +} + +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 1170px; + } + .span12 { + width: 1170px; + } + .span11 { + width: 1070px; + } + .span10 { + width: 970px; + } + .span9 { + width: 870px; + } + .span8 { + width: 770px; + } + .span7 { + width: 670px; + } + .span6 { + width: 570px; + } + .span5 { + width: 470px; + } + .span4 { + width: 370px; + } + .span3 { + width: 270px; + } + .span2 { + width: 170px; + } + .span1 { + width: 70px; + } + .offset12 { + margin-left: 1230px; + } + .offset11 { + margin-left: 1130px; + } + .offset10 { + margin-left: 1030px; + } + .offset9 { + margin-left: 930px; + } + .offset8 { + margin-left: 830px; + } + .offset7 { + margin-left: 730px; + } + .offset6 { + margin-left: 630px; + } + .offset5 { + margin-left: 530px; + } + .offset4 { + margin-left: 430px; + } + .offset3 { + margin-left: 330px; + } + .offset2 { + margin-left: 230px; + } + .offset1 { + margin-left: 130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 28px; + margin-left: 2.564102564%; + *margin-left: 2.510911074638298%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; + } + .row-fluid .span11 { + width: 91.45299145300001%; + *width: 91.3997999636383%; + } + .row-fluid .span10 { + width: 82.905982906%; + *width: 82.8527914166383%; + } + .row-fluid .span9 { + width: 74.358974359%; + *width: 74.30578286963829%; + } + .row-fluid .span8 { + width: 65.81196581200001%; + *width: 65.7587743226383%; + } + .row-fluid .span7 { + width: 57.264957265%; + *width: 57.2117657756383%; + } + .row-fluid .span6 { + width: 48.717948718%; + *width: 48.6647572286383%; + } + .row-fluid .span5 { + width: 40.170940171000005%; + *width: 40.117748681638304%; + } + .row-fluid .span4 { + width: 31.623931624%; + *width: 31.5707401346383%; + } + .row-fluid .span3 { + width: 23.076923077%; + *width: 23.0237315876383%; + } + .row-fluid .span2 { + width: 14.529914530000001%; + *width: 14.4767230406383%; + } + .row-fluid .span1 { + width: 5.982905983%; + *width: 5.929714493638298%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 1160px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 1060px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 960px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 860px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 760px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 660px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 560px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 460px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 360px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 260px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 160px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 60px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } + .row-fluid .thumbnails { + margin-left: 0; + } +} + +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top, + .navbar-fixed-bottom { + position: static; + } + .navbar-fixed-top { + margin-bottom: 18px; + } + .navbar-fixed-bottom { + margin-top: 18px; + } + .navbar-fixed-top .navbar-inner, + .navbar-fixed-bottom .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-right: 10px; + padding-left: 10px; + margin: 0 0 0 -5px; + } + .nav-collapse { + clear: both; + } + .nav-collapse .nav { + float: none; + margin: 0 0 9px; + text-align:center; + } + .nav-collapse .nav > li { + float: none; + } + .nav-collapse .nav > li > a { + margin-bottom: 2px; + } + .nav-collapse .nav > .divider-vertical { + display: none; + } + .nav-collapse .nav .nav-header { + color: #999999; + text-shadow: none; + } + .nav-collapse .nav > li > a, + .nav-collapse .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .nav-collapse .btn { + padding: 4px 10px 4px; + font-weight: normal; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + } + .nav-collapse .dropdown-menu li + li a { + margin-bottom: 2px; + } + .nav-collapse .nav > li > a:hover, + .nav-collapse .dropdown-menu a:hover { + background-color: #222222; + } + .nav-collapse.in .btn-group { + padding: 0; + margin-top: 5px; + } + .nav-collapse .dropdown-menu { + position: static; + top: auto; + left: auto; + display: block; + float: none; + max-width: none; + padding: 0; + margin: 0 15px; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .nav-collapse .dropdown-menu:before, + .nav-collapse .dropdown-menu:after { + display: none; + } + .nav-collapse .dropdown-menu .divider { + display: none; + } + .nav-collapse .navbar-form, + .nav-collapse .navbar-search { + float: none; + text-align:center; + margin: 9px 0; + border-top: none; + border-bottom: none; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + padding-bottom:8px; + background:#f1f1f1; + border-radius:0 0 4px 4px; + } + + .alloyMenu .navbar .nav-collapse .nav > li.active > a, .alloyMenu .navbar .nav-collapse .nav > li.active > a:hover, .alloyMenu .navbar .nav-collapse .nav > li > a:hover + { + background:#2980BD; + color:#fff; + border:none; + } + + .alloyMenu .navbar .nav-collapse .nav > li > a.theme1:hover, .alloyMenu .navbar .nav-collapse .nav>li.active>a.theme1 + { + background:#EB5E31; + color:#fff; + border:none; + } + + .alloyMenu .navbar .nav-collapse .nav > li > a.theme2:hover, .alloyMenu .navbar .nav-collapse .nav>li.active>a.theme2 + { + background:#BF5D8C; + color:#fff; + border:none; + } + + .alloyMenu .navbar .nav-collapse .nav > li > a.theme3:hover, .alloyMenu .navbar .nav-collapse .nav>li.active>a.theme3 + { + background:#9FC733; + color:#fff; + border:none; + } + + .navbar .nav-collapse .nav.pull-right { + float: none; + margin-left: 0; + } + .nav-collapse, + .nav-collapse.collapse { + height: 0; + overflow: hidden; + } + .navbar .btn-navbar { + display: block; + } + .navbar-static .navbar-inner { + padding-right: 10px; + padding-left: 10px; + } +} + +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + overflow: visible !important; + } +} diff --git a/src/alloy/Static/css/bootstrap.css b/src/alloy/Static/css/bootstrap.css new file mode 100644 index 0000000..94a65f3 --- /dev/null +++ b/src/alloy/Static/css/bootstrap.css @@ -0,0 +1,5022 @@ +/*! + * Bootstrap v2.0.4 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} + +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +audio:not([controls]) { + display: none; +} + +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +a:hover, +a:active { + outline: 0; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + max-width: 100%; + vertical-align: middle; + border: 0; + -ms-interpolation-mode: bicubic; +} + +#map_canvas img { + max-width: none; +} + +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} + +button, +input { + *overflow: visible; + line-height: normal; +} + +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} + +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} + +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} + +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} + +textarea { + overflow: auto; + vertical-align: top; +} + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 28px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; +} + +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} + +a { + color: #2980bd; + text-decoration: none; +} + +a:hover { + color: #005580; + +} + +.row { + margin-left: -20px; + *zoom: 1; +} + +.row:before, +.row:after { + display: table; + content: ""; + clear:both; +} + +.row:after { + clear: both; +} + +[class*="span"] { + float: left; + margin-left: 20px; +} + +.container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.span12 { + width: 940px; +} + +.span11 { + width: 860px; +} + +.span10 { + width: 780px; +} + +.span9 { + width: 700px; +} + +.span8 { + width: 620px; +} + +.span7 { + width: 540px; +} + +.span6 { + width: 460px; +} + +.span5 { + width: 380px; +} + +.span4 { + width: 300px; +} + +.span3 { + width: 220px; +} + +.span2 { + width: 140px; +} + +.span1 { + width: 60px; +} + +.offset12 { + margin-left: 980px; +} + +.offset11 { + margin-left: 900px; +} + +.offset10 { + margin-left: 820px; +} + +.offset9 { + margin-left: 740px; +} + +.offset8 { + margin-left: 660px; +} + +.offset7 { + margin-left: 580px; +} + +.offset6 { + margin-left: 500px; +} + +.offset5 { + margin-left: 420px; +} + +.offset4 { + margin-left: 340px; +} + +.offset3 { + margin-left: 260px; +} + +.offset2 { + margin-left: 180px; +} + +.offset1 { + margin-left: 100px; +} + +.row-fluid { + width: 100%; + *zoom: 1; +} + +.row-fluid:before, +.row-fluid:after { + display: table; + content: ""; +} + +.row-fluid:after { + clear: both; +} + +.row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 28px; + margin-left: 2.127659574%; + *margin-left: 2.0744680846382977%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; +} + +.row-fluid [class*="span"]:first-child { + margin-left: 0; +} + +.row-fluid .span12 { + width: 99.99999998999999%; + *width: 99.94680850063828%; +} + +.row-fluid .span11 { + width: 91.489361693%; + *width: 91.4361702036383%; +} + +.row-fluid .span10 { + width: 82.97872339599999%; + *width: 82.92553190663828%; +} + +.row-fluid .span9 { + width: 74.468085099%; + *width: 74.4148936096383%; +} + +.row-fluid .span8 { + width: 65.95744680199999%; + *width: 65.90425531263828%; +} + +.row-fluid .span7 { + width: 57.446808505%; + *width: 57.3936170156383%; +} + +.row-fluid .span6 { + width: 48.93617020799999%; + *width: 48.88297871863829%; +} + +.row-fluid .span5 { + width: 40.425531911%; + *width: 40.3723404216383%; +} + +.row-fluid .span4 { + width: 31.914893614%; + *width: 31.8617021246383%; +} + +.row-fluid .span3 { + width: 23.404255317%; + *width: 23.3510638276383%; +} + +.row-fluid .span2 { + width: 14.89361702%; + *width: 14.8404255306383%; +} + +.row-fluid .span1 { + width: 6.382978723%; + *width: 6.329787233638298%; +} + +.container { + margin-right: auto; + margin-left: auto; + *zoom: 1; +} + +.container:before, +.container:after { + display: table; + content: ""; +} + +.container:after { + clear: both; +} + +.container-fluid { + padding-right: 20px; + padding-left: 20px; + *zoom: 1; +} + +.container-fluid:before, +.container-fluid:after { + display: table; + content: ""; +} + +.container-fluid:after { + clear: both; +} + +p { + margin: 0 0 9px; +} + +p small { + font-size: 11px; + color: #999999; +} + +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-family: inherit; + font-weight: bold; + color: inherit; + text-rendering: optimizelegibility; +} + +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} + +h1 { + font-size: 30px; + line-height: 36px; +} + +h1 small { + font-size: 18px; +} + +h2 { + font-size: 2em; + line-height: 36px; +} + +h2 small { + font-size: 18px; +} + +h3 { + font-size: 1.7em; + line-height: 30px; +} + +h3 small { + font-size: 14px; +} + +h4, +h5, +h6 { + line-height: 18px; +} + +h4 { + font-size: 14px; +} + +h4 small { + font-size: 12px; +} + +h5 { + font-size: 12px; +} + +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} + +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} + +.page-header h1 { + line-height: 1; +} + +ul, +ol { + padding: 0; + margin: 0 0 9px 25px; +} + +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} + +ul { + list-style: disc; +} + +ol { + list-style: decimal; +} + +li { + line-height: 18px; +} + +ul.unstyled, +ol.unstyled { + margin-left: 0; + list-style: none; +} + +dl { + margin-bottom: 18px; +} + +dt, +dd { + line-height: 18px; +} + +dt { + font-weight: bold; + line-height: 17px; +} + +dd { + margin-left: 9px; +} + +.dl-horizontal dt { + float: left; + width: 120px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +.dl-horizontal dd { + margin-left: 130px; +} + +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +.muted { + color: #999999; +} + +abbr[title] { + cursor: help; + border-bottom: 1px dotted #999999; +} + +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} + +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} + +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} + +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} + +blockquote small:before { + content: '\2014 \00A0'; +} + +blockquote.pull-right { + float: right; + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; +} + +blockquote.pull-right p, +blockquote.pull-right small { + text-align: right; +} + +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +address { + display: block; + margin-bottom: 18px; + font-style: normal; + line-height: 18px; +} + +small { + font-size: 100%; +} + +cite { + font-style: normal; +} + +code, +pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +code { + padding: 2px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} + +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12.025px; + line-height: 18px; + word-break: break-all; + word-wrap: break-word; + white-space: pre; + white-space: pre-wrap; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +pre.prettyprint { + margin-bottom: 18px; +} + +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} + +form { + margin: 0 0 18px; +} + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} + +legend small { + font-size: 13.5px; + color: #999999; +} + + +fieldset legend +{ + border:0; + font-size:1em; + margin-bottom:5px; + } + +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} + +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +label { + display: block; + margin-bottom: 5px; +} + +select, +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + display: inline-block; + height: 18px; + padding: 4px; + margin-bottom: 15px; + font-size: 13px; + line-height: 18px; + color: #555555; +} + +input, +textarea { + width: 98%; + max-width:620px; +} + +textarea { + height: auto; +} + +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + background-color: #ffffff; + border: 1px solid #cccccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} + +textarea:focus, +input[type="text"]:focus, +input[type="password"]:focus, +input[type="datetime"]:focus, +input[type="datetime-local"]:focus, +input[type="date"]:focus, +input[type="month"]:focus, +input[type="time"]:focus, +input[type="week"]:focus, +input[type="number"]:focus, +input[type="email"]:focus, +input[type="url"]:focus, +input[type="search"]:focus, +input[type="tel"]:focus, +input[type="color"]:focus, +.uneditable-input:focus { + border-color: rgba(82, 168, 236, 0.8); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); +} + +input[type="radio"], +input[type="checkbox"] { + margin: -1px 0 0 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; +} + +input[type="submit"], +input[type="reset"], +input[type="button"], +input[type="radio"], +input[type="checkbox"] { + width: auto; +} + +.uneditable-textarea { + width: auto; + height: auto; +} + +select, +input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} + +select { + width: 220px; + border: 1px solid #bbb; +} + +select[multiple], +select[size] { + height: auto; +} + +select:focus, +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.radio, +.checkbox { + min-height: 18px; + padding-left: 18px; +} + +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} + +.controls > .radio:first-child, +.controls > .checkbox:first-child { + padding-top: 5px; +} + +.radio.inline, +.checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} + +.radio.inline + .radio.inline, +.checkbox.inline + .checkbox.inline { + margin-left: 10px; +} + +.input-mini { + width: 60px; +} + +.input-small { + width: 90px; +} + +.input-medium { + width: 150px; +} + +.input-large { + width: 210px; +} + +.input-xlarge { + width: 270px; +} + +.input-xxlarge { + width: 530px; +} + +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"] { + float: none; + margin-left: 0; +} + +.input-append input[class*="span"], +.input-append .uneditable-input[class*="span"], +.input-prepend input[class*="span"], +.input-prepend .uneditable-input[class*="span"], +.row-fluid .input-prepend [class*="span"], +.row-fluid .input-append [class*="span"] { + display: inline-block; +} + +input, +textarea, +.uneditable-input { + margin-left: 0; +} + +input.span12, +textarea.span12, +.uneditable-input.span12 { + width: 930px; +} + +input.span11, +textarea.span11, +.uneditable-input.span11 { + width: 850px; +} + +input.span10, +textarea.span10, +.uneditable-input.span10 { + width: 770px; +} + +input.span9, +textarea.span9, +.uneditable-input.span9 { + width: 690px; +} + +input.span8, +textarea.span8, +.uneditable-input.span8 { + width: 610px; +} + +input.span7, +textarea.span7, +.uneditable-input.span7 { + width: 530px; +} + +input.span6, +textarea.span6, +.uneditable-input.span6 { + width: 450px; +} + +input.span5, +textarea.span5, +.uneditable-input.span5 { + width: 370px; +} + +input.span4, +textarea.span4, +.uneditable-input.span4 { + width: 290px; +} + +input.span3, +textarea.span3, +.uneditable-input.span3 { + width: 210px; +} + +input.span2, +textarea.span2, +.uneditable-input.span2 { + width: 130px; +} + +input.span1, +textarea.span1, +.uneditable-input.span1 { + width: 50px; +} + +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + cursor: not-allowed; + background-color: #eeeeee; + border-color: #ddd; +} + +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"][readonly], +input[type="checkbox"][readonly] { + background-color: transparent; +} + +.control-group.warning > label, +.control-group.warning .help-block, +.control-group.warning .help-inline { + color: #c09853; +} + +.control-group.warning .checkbox, +.control-group.warning .radio, +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} + +.control-group.warning .checkbox:focus, +.control-group.warning .radio:focus, +.control-group.warning input:focus, +.control-group.warning select:focus, +.control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} + +.control-group.warning .input-prepend .add-on, +.control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} + +.control-group.error > label, +.control-group.error .help-block, +.control-group.error .help-inline { + color: #b94a48; +} + +.control-group.error .checkbox, +.control-group.error .radio, +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} + +.control-group.error .checkbox:focus, +.control-group.error .radio:focus, +.control-group.error input:focus, +.control-group.error select:focus, +.control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} + +.control-group.error .input-prepend .add-on, +.control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} + +.control-group.success > label, +.control-group.success .help-block, +.control-group.success .help-inline { + color: #468847; +} + +.control-group.success .checkbox, +.control-group.success .radio, +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + color: #468847; + border-color: #468847; +} + +.control-group.success .checkbox:focus, +.control-group.success .radio:focus, +.control-group.success input:focus, +.control-group.success select:focus, +.control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} + +.control-group.success .input-prepend .add-on, +.control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} + +input:focus:required:invalid, +textarea:focus:required:invalid, +select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} + +input:focus:required:invalid:focus, +textarea:focus:required:invalid:focus, +select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} + +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #e5e5e5; + *zoom: 1; +} + +.form-actions:before, +.form-actions:after { + display: table; + content: ""; +} + +.form-actions:after { + clear: both; +} + +.uneditable-input { + overflow: hidden; + white-space: nowrap; + cursor: not-allowed; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); +} + +:-moz-placeholder { + color: #999999; +} + +:-ms-input-placeholder { + color: #999999; +} + +::-webkit-input-placeholder { + color: #999999; +} + +.help-block, +.help-inline { + color: #555555; +} + +.help-block { + display: block; + margin-bottom: 9px; +} + +.help-inline { + display: inline-block; + *display: inline; + padding-left: 5px; + vertical-align: middle; + *zoom: 1; +} + +.input-prepend, +.input-append { + margin-bottom: 5px; +} + +.input-prepend input, +.input-append input, +.input-prepend select, +.input-append select, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + position: relative; + margin-bottom: 0; + *margin-left: 0; + vertical-align: middle; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.input-prepend input:focus, +.input-append input:focus, +.input-prepend select:focus, +.input-append select:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + z-index: 2; +} + +.input-prepend .uneditable-input, +.input-append .uneditable-input { + border-left-color: #ccc; +} + +.input-prepend .add-on, +.input-append .add-on { + display: inline-block; + width: auto; + height: 18px; + min-width: 16px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + vertical-align: middle; + background-color: #eeeeee; + border: 1px solid #ccc; +} + +.input-prepend .add-on, +.input-append .add-on, +.input-prepend .btn, +.input-append .btn { + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-prepend .active, +.input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} + +.input-prepend .add-on, +.input-prepend .btn { + margin-right: -1px; +} + +.input-prepend .add-on:first-child, +.input-prepend .btn:first-child { + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.input-append input, +.input-append select, +.input-append .uneditable-input { + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.input-append .uneditable-input { + border-right-color: #ccc; + border-left-color: #eee; +} + +.input-append .add-on:last-child, +.input-append .btn:last-child { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.input-prepend.input-append input, +.input-prepend.input-append select, +.input-prepend.input-append .uneditable-input { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-prepend.input-append .add-on:first-child, +.input-prepend.input-append .btn:first-child { + margin-right: -1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.input-prepend.input-append .add-on:last-child, +.input-prepend.input-append .btn:last-child { + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.search-query { + padding-right: 14px; + padding-right: 4px \9; + padding-left: 14px; + padding-left: 4px \9; + /* IE7-8 doesn't have border-radius, so don't indent the padding */ + + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} + +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input, +.form-search .input-prepend, +.form-inline .input-prepend, +.form-horizontal .input-prepend, +.form-search .input-append, +.form-inline .input-append, +.form-horizontal .input-append { + display: inline-block; + *display: inline; + margin-bottom: 0; + *zoom: 1; +} + +.form-search .hide, +.form-inline .hide, +.form-horizontal .hide { + display: none; +} + +.form-search label, +.form-inline label { + display: inline-block; +} + +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + margin-bottom: 0; +} + +.form-search .radio, +.form-search .checkbox, +.form-inline .radio, +.form-inline .checkbox { + padding-left: 0; + margin-bottom: 0; + vertical-align: middle; +} + +.form-search .radio input[type="radio"], +.form-search .checkbox input[type="checkbox"], +.form-inline .radio input[type="radio"], +.form-inline .checkbox input[type="checkbox"] { + float: left; + margin-right: 3px; + margin-left: 0; +} + +.control-group { + margin-bottom: 9px; +} + +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} + +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} + +.form-horizontal .control-group:before, +.form-horizontal .control-group:after { + display: table; + content: ""; +} + +.form-horizontal .control-group:after { + clear: both; +} + +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} + +.form-horizontal .controls { + *display: inline-block; + *padding-left: 20px; + margin-left: 160px; + *margin-left: 0; +} + +.form-horizontal .controls:first-child { + *padding-left: 160px; +} + +.form-horizontal .help-block { + margin-top: 9px; + margin-bottom: 0; +} + +.form-horizontal .form-actions { + padding-left: 160px; +} + +table { + max-width: 100%; + background-color: transparent; + border-collapse: collapse; + border-spacing: 0; +} + +.table { + width: 100%; + margin-bottom: 18px; +} + +.table th, +.table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #dddddd; +} + +.table th { + font-weight: bold; +} + +.table thead th { + vertical-align: bottom; +} + +.table caption + thead tr:first-child th, +.table caption + thead tr:first-child td, +.table colgroup + thead tr:first-child th, +.table colgroup + thead tr:first-child td, +.table thead:first-child tr:first-child th, +.table thead:first-child tr:first-child td { + border-top: 0; +} + +.table tbody + tbody { + border-top: 2px solid #dddddd; +} + +.table-condensed th, +.table-condensed td { + padding: 4px 5px; +} + +.table-bordered { + border: 1px solid #dddddd; + border-collapse: separate; + *border-collapse: collapsed; + border-left: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.table-bordered th, +.table-bordered td { + border-left: 1px solid #dddddd; +} + +.table-bordered caption + thead tr:first-child th, +.table-bordered caption + tbody tr:first-child th, +.table-bordered caption + tbody tr:first-child td, +.table-bordered colgroup + thead tr:first-child th, +.table-bordered colgroup + tbody tr:first-child th, +.table-bordered colgroup + tbody tr:first-child td, +.table-bordered thead:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} + +.table-bordered thead:first-child tr:first-child th:first-child, +.table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.table-bordered thead:first-child tr:first-child th:last-child, +.table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; +} + +.table-bordered thead:last-child tr:last-child th:first-child, +.table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; +} + +.table-bordered thead:last-child tr:last-child th:last-child, +.table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; +} + +.table-striped tbody tr:nth-child(odd) td, +.table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} + +.table tbody tr:hover td, +.table tbody tr:hover th { + background-color: #f5f5f5; +} + +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} + +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} + +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} + +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} + +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} + +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} + +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} + +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} + +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} + +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} + +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} + +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} + +table .span13 { + float: none; + width: 1004px; + margin-left: 0; +} + +table .span14 { + float: none; + width: 1084px; + margin-left: 0; +} + +table .span15 { + float: none; + width: 1164px; + margin-left: 0; +} + +table .span16 { + float: none; + width: 1244px; + margin-left: 0; +} + +table .span17 { + float: none; + width: 1324px; + margin-left: 0; +} + +table .span18 { + float: none; + width: 1404px; + margin-left: 0; +} + +table .span19 { + float: none; + width: 1484px; + margin-left: 0; +} + +table .span20 { + float: none; + width: 1564px; + margin-left: 0; +} + +table .span21 { + float: none; + width: 1644px; + margin-left: 0; +} + +table .span22 { + float: none; + width: 1724px; + margin-left: 0; +} + +table .span23 { + float: none; + width: 1804px; + margin-left: 0; +} + +table .span24 { + float: none; + width: 1884px; + margin-left: 0; +} + +[class^="icon-"], +[class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + *margin-right: .3em; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; +} + +[class^="icon-"]:last-child, +[class*=" icon-"]:last-child { + *margin-left: 0; +} + +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} + +.icon-glass { + background-position: 0 0; +} + +.icon-music { + background-position: -24px 0; +} + +.icon-search { + background-position: -48px 0; +} + +.icon-envelope { + background-position: -72px 0; +} + +.icon-heart { + background-position: -96px 0; +} + +.icon-star { + background-position: -120px 0; +} + +.icon-star-empty { + background-position: -144px 0; +} + +.icon-user { + background-position: -168px 0; +} + +.icon-film { + background-position: -192px 0; +} + +.icon-th-large { + background-position: -216px 0; +} + +.icon-th { + background-position: -240px 0; +} + +.icon-th-list { + background-position: -264px 0; +} + +.icon-ok { + background-position: -288px 0; +} + +.icon-remove { + background-position: -312px 0; +} + +.icon-zoom-in { + background-position: -336px 0; +} + +.icon-zoom-out { + background-position: -360px 0; +} + +.icon-off { + background-position: -384px 0; +} + +.icon-signal { + background-position: -408px 0; +} + +.icon-cog { + background-position: -432px 0; +} + +.icon-trash { + background-position: -456px 0; +} + +.icon-home { + background-position: 0 -24px; +} + +.icon-file { + background-position: -24px -24px; +} + +.icon-time { + background-position: -48px -24px; +} + +.icon-road { + background-position: -72px -24px; +} + +.icon-download-alt { + background-position: -96px -24px; +} + +.icon-download { + background-position: -120px -24px; +} + +.icon-upload { + background-position: -144px -24px; +} + +.icon-inbox { + background-position: -168px -24px; +} + +.icon-play-circle { + background-position: -192px -24px; +} + +.icon-repeat { + background-position: -216px -24px; +} + +.icon-refresh { + background-position: -240px -24px; +} + +.icon-list-alt { + background-position: -264px -24px; +} + +.icon-lock { + background-position: -287px -24px; +} + +.icon-flag { + background-position: -312px -24px; +} + +.icon-headphones { + background-position: -336px -24px; +} + +.icon-volume-off { + background-position: -360px -24px; +} + +.icon-volume-down { + background-position: -384px -24px; +} + +.icon-volume-up { + background-position: -408px -24px; +} + +.icon-qrcode { + background-position: -432px -24px; +} + +.icon-barcode { + background-position: -456px -24px; +} + +.icon-tag { + background-position: 0 -48px; +} + +.icon-tags { + background-position: -25px -48px; +} + +.icon-book { + background-position: -48px -48px; +} + +.icon-bookmark { + background-position: -72px -48px; +} + +.icon-print { + background-position: -96px -48px; +} + +.icon-camera { + background-position: -120px -48px; +} + +.icon-font { + background-position: -144px -48px; +} + +.icon-bold { + background-position: -167px -48px; +} + +.icon-italic { + background-position: -192px -48px; +} + +.icon-text-height { + background-position: -216px -48px; +} + +.icon-text-width { + background-position: -240px -48px; +} + +.icon-align-left { + background-position: -264px -48px; +} + +.icon-align-center { + background-position: -288px -48px; +} + +.icon-align-right { + background-position: -312px -48px; +} + +.icon-align-justify { + background-position: -336px -48px; +} + +.icon-list { + background-position: -360px -48px; +} + +.icon-indent-left { + background-position: -384px -48px; +} + +.icon-indent-right { + background-position: -408px -48px; +} + +.icon-facetime-video { + background-position: -432px -48px; +} + +.icon-picture { + background-position: -456px -48px; +} + +.icon-pencil { + background-position: 0 -72px; +} + +.icon-map-marker { + background-position: -24px -72px; +} + +.icon-adjust { + background-position: -48px -72px; +} + +.icon-tint { + background-position: -72px -72px; +} + +.icon-edit { + background-position: -96px -72px; +} + +.icon-share { + background-position: -120px -72px; +} + +.icon-check { + background-position: -144px -72px; +} + +.icon-move { + background-position: -168px -72px; +} + +.icon-step-backward { + background-position: -192px -72px; +} + +.icon-fast-backward { + background-position: -216px -72px; +} + +.icon-backward { + background-position: -240px -72px; +} + +.icon-play { + background-position: -264px -72px; +} + +.icon-pause { + background-position: -288px -72px; +} + +.icon-stop { + background-position: -312px -72px; +} + +.icon-forward { + background-position: -336px -72px; +} + +.icon-fast-forward { + background-position: -360px -72px; +} + +.icon-step-forward { + background-position: -384px -72px; +} + +.icon-eject { + background-position: -408px -72px; +} + +.icon-chevron-left { + background-position: -432px -72px; +} + +.icon-chevron-right { + background-position: -456px -72px; +} + +.icon-plus-sign { + background-position: 0 -96px; +} + +.icon-minus-sign { + background-position: -24px -96px; +} + +.icon-remove-sign { + background-position: -48px -96px; +} + +.icon-ok-sign { + background-position: -72px -96px; +} + +.icon-question-sign { + background-position: -96px -96px; +} + +.icon-info-sign { + background-position: -120px -96px; +} + +.icon-screenshot { + background-position: -144px -96px; +} + +.icon-remove-circle { + background-position: -168px -96px; +} + +.icon-ok-circle { + background-position: -192px -96px; +} + +.icon-ban-circle { + background-position: -216px -96px; +} + +.icon-arrow-left { + background-position: -240px -96px; +} + +.icon-arrow-right { + background-position: -264px -96px; +} + +.icon-arrow-up { + background-position: -289px -96px; +} + +.icon-arrow-down { + background-position: -312px -96px; +} + +.icon-share-alt { + background-position: -336px -96px; +} + +.icon-resize-full { + background-position: -360px -96px; +} + +.icon-resize-small { + background-position: -384px -96px; +} + +.icon-plus { + background-position: -408px -96px; +} + +.icon-minus { + background-position: -433px -96px; +} + +.icon-asterisk { + background-position: -456px -96px; +} + +.icon-exclamation-sign { + background-position: 0 -120px; +} + +.icon-gift { + background-position: -24px -120px; +} + +.icon-leaf { + background-position: -48px -120px; +} + +.icon-fire { + background-position: -72px -120px; +} + +.icon-eye-open { + background-position: -96px -120px; +} + +.icon-eye-close { + background-position: -120px -120px; +} + +.icon-warning-sign { + background-position: -144px -120px; +} + +.icon-plane { + background-position: -168px -120px; +} + +.icon-calendar { + background-position: -192px -120px; +} + +.icon-random { + background-position: -216px -120px; +} + +.icon-comment { + background-position: -240px -120px; +} + +.icon-magnet { + background-position: -264px -120px; +} + +.icon-chevron-up { + background-position: -288px -120px; +} + +.icon-chevron-down { + background-position: -313px -119px; +} + +.icon-retweet { + background-position: -336px -120px; +} + +.icon-shopping-cart { + background-position: -360px -120px; +} + +.icon-folder-close { + background-position: -384px -120px; +} + +.icon-folder-open { + background-position: -408px -120px; +} + +.icon-resize-vertical { + background-position: -432px -119px; +} + +.icon-resize-horizontal { + background-position: -456px -118px; +} + +.icon-hdd { + background-position: 0 -144px; +} + +.icon-bullhorn { + background-position: -24px -144px; +} + +.icon-bell { + background-position: -48px -144px; +} + +.icon-certificate { + background-position: -72px -144px; +} + +.icon-thumbs-up { + background-position: -96px -144px; +} + +.icon-thumbs-down { + background-position: -120px -144px; +} + +.icon-hand-right { + background-position: -144px -144px; +} + +.icon-hand-left { + background-position: -168px -144px; +} + +.icon-hand-up { + background-position: -192px -144px; +} + +.icon-hand-down { + background-position: -216px -144px; +} + +.icon-circle-arrow-right { + background-position: -240px -144px; +} + +.icon-circle-arrow-left { + background-position: -264px -144px; +} + +.icon-circle-arrow-up { + background-position: -288px -144px; +} + +.icon-circle-arrow-down { + background-position: -312px -144px; +} + +.icon-globe { + background-position: -336px -144px; +} + +.icon-wrench { + background-position: -360px -144px; +} + +.icon-tasks { + background-position: -384px -144px; +} + +.icon-filter { + background-position: -408px -144px; +} + +.icon-briefcase { + background-position: -432px -144px; +} + +.icon-fullscreen { + background-position: -456px -144px; +} + +.dropup, +.dropdown { + position: relative; +} + +.dropdown-toggle { + *margin-bottom: -3px; +} + +.dropdown-toggle:active, +.open .dropdown-toggle { + outline: 0; +} + +.caret { + display: inline-block; + width: 0; + height: 0; + vertical-align: top; + border-top: 4px solid #000000; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + content: ""; + opacity: 0.3; + filter: alpha(opacity=30); +} + +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} + +.dropdown:hover .caret, +.open .caret { + opacity: 1; + filter: alpha(opacity=100); +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 4px 0; + margin: 1px 0 0; + list-style: none; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + *border-right-width: 2px; + *border-bottom-width: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.dropdown-menu .divider { + *width: 100%; + height: 1px; + margin: 8px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #333333; + white-space: nowrap; +} + +.dropdown-menu li > a:hover, +.dropdown-menu .active > a, +.dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #2980bd; +} + +.open { + *z-index: 1000; +} + +.open > .dropdown-menu { + display: block; +} + +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} + +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px solid #000000; + content: "\2191"; +} + +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} + +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} + +.well-large { + padding: 24px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.well-small { + padding: 9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} + +.fade.in { + opacity: 1; +} + +.collapse { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; +} + +.collapse.in { + height: auto; +} + +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} + +.close:hover { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.4; + filter: alpha(opacity=40); +} + +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} + +.btn, button[type="submit"], input[type="submit"] { + display: inline-block; + *display: inline; + padding: 4px 10px 4px; + margin-bottom: 0; + *margin-left: .3em; + font-size: 1em; + line-height: 18px; + *line-height: 20px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + cursor: pointer; + background-color: #f5f5f5; + *background-color: #e6e6e6; + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + border: 1px solid #cccccc; + *border: 0; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-bottom-color: #b3b3b3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; + *background-color: #d9d9d9; +} + +.btn:active, +.btn.active { + background-color: #cccccc \9; +} + +.btn:first-child { + *margin-left: 0; +} + +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + *background-color: #d9d9d9; + /* Buttons in IE7 don't get borders, so darken on hover */ + + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} + +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.btn.active, +.btn:active { + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn.disabled, +.btn[disabled] { + cursor: default; + background-color: #e6e6e6; + background-image: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.btn-large [class^="icon-"] { + margin-top: 1px; +} + +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} + +.btn-small [class^="icon-"] { + margin-top: -1px; +} + +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} + +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-inverse.active { + color: rgba(255, 255, 255, 0.75); +} + +.btn { + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +} + +.btn-primary { + background-color: #0074cc; + *background-color: #0055cc; + background-image: -ms-linear-gradient(top, #0088cc, #0055cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0055cc); + background-image: -o-linear-gradient(top, #0088cc, #0055cc); + background-image: -moz-linear-gradient(top, #0088cc, #0055cc); + background-image: linear-gradient(top, #0088cc, #0055cc); + background-repeat: repeat-x; + border-color: #0055cc #0055cc #003580; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0055cc; + *background-color: #004ab3; +} + +.btn-primary:active, +.btn-primary.active { + background-color: #004099 \9; +} + +.btn-primary:hover, .btnCheckbox:hover, +.btn-primary:active, .btnCheckbox.active { + background-color: #0088cc; + *background-color: #0088cc; + background-image: -ms-linear-gradient(top, #0055cc, #0088cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0055cc), to(#0088cc)); + background-image: -webkit-linear-gradient(top, #0055cc, #0088cc); + background-image: -o-linear-gradient(top, #0055cc, #0088cc); + background-image: -moz-linear-gradient(top, #0055cc, #0088cc); + background-image: linear-gradient(top, #0055cc, #0088cc); + background-repeat: repeat-x; + border-color: #0088cc #0088cc #003580; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#0055cc', endColorstr='#0088cc', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); + color:#fff; + +} + +.btn-warning { + background-color: #faa732; + *background-color: #f89406; + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; + *background-color: #df8505; +} + +.btn-warning:active, +.btn-warning.active { + background-color: #c67605 \9; +} + +.btn-danger { + background-color: #da4f49; + *background-color: #bd362f; + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; + *background-color: #a9302a; +} + +.btn-danger:active, +.btn-danger.active { + background-color: #942a25 \9; +} + +.btn-success { + background-color: #5bb75b; + *background-color: #51a351; + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; + *background-color: #499249; +} + +.btn-success:active, +.btn-success.active { + background-color: #408140 \9; +} + +.btn-info { + background-color: #49afcd; + *background-color: #2f96b4; + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; + *background-color: #2a85a0; +} + +.btn-info:active, +.btn-info.active { + background-color: #24748c \9; +} + +.btn-inverse { + background-color: #414141; + *background-color: #222222; + background-image: -ms-linear-gradient(top, #555555, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222)); + background-image: -webkit-linear-gradient(top, #555555, #222222); + background-image: -o-linear-gradient(top, #555555, #222222); + background-image: -moz-linear-gradient(top, #555555, #222222); + background-image: linear-gradient(top, #555555, #222222); + background-repeat: repeat-x; + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #222222; + *background-color: #151515; +} + +.btn-inverse:active, +.btn-inverse.active { + background-color: #080808 \9; +} + +button.btn, +input[type="submit"].btn, input[type="submit"], button[type="submit"] { + *padding-top: 2px; + *padding-bottom: 2px; + width:100%; + max-width:170px; + height:50px; + border-radius:4px; + font-size:1.2em; +} + +button.btn::-moz-focus-inner, +input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} + +button.btn.btn-large, +input[type="submit"].btn.btn-large { + *padding-top: 7px; + *padding-bottom: 7px; +} + +button.btn.btn-small, +input[type="submit"].btn.btn-small { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn.btn-mini, +input[type="submit"].btn.btn-mini { + *padding-top: 1px; + *padding-bottom: 1px; +} + +.btn-group { + position: relative; + *margin-left: .3em; + *zoom: 1; +} + +.btn-group:before, +.btn-group:after { + display: table; + content: ""; +} + +.btn-group:after { + clear: both; +} + +.btn-group:first-child { + *margin-left: 0; +} + +.btn-group + .btn-group { + margin-left: 5px; +} + +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} + +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} + +.btn-group > .btn, .btn-group > .btnCheckbox { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group > .btn:first-child, .btn-group > .btnCheckbox:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 4px; +} + +.btn-group > .btn:last-child, .btn-group > .btnCheckbox:last-child, +.btn-group > .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; +} + +.btn-group > .btn.large:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.btn-group > .btn.large:last-child, +.btn-group > .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active { + z-index: 2; +} + +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + +.btn-group > .dropdown-toggle { + *padding-top: 4px; + padding-right: 8px; + *padding-bottom: 4px; + padding-left: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group > .btn-mini.dropdown-toggle { + padding-right: 5px; + padding-left: 5px; +} + +.btn-group > .btn-small.dropdown-toggle { + *padding-top: 4px; + *padding-bottom: 4px; +} + +.btn-group > .btn-large.dropdown-toggle { + padding-right: 12px; + padding-left: 12px; +} + +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group.open .btn.dropdown-toggle { + background-color: #e6e6e6; +} + +.btn-group.open .btn-primary.dropdown-toggle { + background-color: #0055cc; +} + +.btn-group.open .btn-warning.dropdown-toggle { + background-color: #f89406; +} + +.btn-group.open .btn-danger.dropdown-toggle { + background-color: #bd362f; +} + +.btn-group.open .btn-success.dropdown-toggle { + background-color: #51a351; +} + +.btn-group.open .btn-info.dropdown-toggle { + background-color: #2f96b4; +} + +.btn-group.open .btn-inverse.dropdown-toggle { + background-color: #222222; +} + +.btn .caret { + margin-top: 7px; + margin-left: 0; +} + +.btn:hover .caret, +.open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} + +.btn-mini .caret { + margin-top: 5px; +} + +.btn-small .caret { + margin-top: 6px; +} + +.btn-large .caret { + margin-top: 6px; + border-top-width: 5px; + border-right-width: 5px; + border-left-width: 5px; +} + +.dropup .btn-large .caret { + border-top: 0; + border-bottom: 5px solid #000000; +} + +.btn-primary .caret, +.btn-warning .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} + +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + color: #c09853; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.alert-heading { + color: inherit; +} + +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} + +.alert-success { + color: #468847; + background-color: #dff0d8; + border-color: #d6e9c6; +} + +.alert-danger, +.alert-error { + color: #b94a48; + background-color: #f2dede; + border-color: #eed3d7; +} + +.alert-info { + color: #3a87ad; + background-color: #d9edf7; + border-color: #bce8f1; +} + +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} + +.alert-block > p, +.alert-block > ul { + margin-bottom: 0; +} + +.alert-block p + p { + margin-top: 5px; +} + +.nav { + margin-bottom: 18px; + margin-left: 0; + list-style: none; +} + +.nav > li > a { + display: block; +} + +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} + +.nav > .pull-right { + float: right; +} + +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} + +.nav li + .nav-header { + margin-top: 9px; +} + +.nav-list { + padding-right: 15px; + padding-left: 15px; + margin-bottom: 0; +} + +.nav-list > li > a, +.nav-list .nav-header { + margin-right: -15px; + margin-left: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} + +.nav-list > li > a { + padding: 3px 15px; +} + +.nav-list > .active > a, +.nav-list > .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} + +.nav-list [class^="icon-"] { + margin-right: 2px; +} + +.nav-list .divider { + *width: 100%; + height: 1px; + margin: 8px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.nav-tabs, +.nav-pills { + *zoom: 1; +} + +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} + +.nav-tabs:after, +.nav-pills:after { + clear: both; +} + +.nav-tabs > li, +.nav-pills > li { + float: left; +} + +.nav-tabs > li > a, +.nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} + +.nav-tabs { + border-bottom: 1px solid #ddd; +} + +.nav-tabs > li { + margin-bottom: -1px; +} + +.nav-tabs > li > a { + padding-top: 8px; + padding-bottom: 8px; + line-height: 18px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} + +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover { + color: #555555; + cursor: default; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; +} + +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.nav-pills > .active > a, +.nav-pills > .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} + +.nav-stacked > li { + float: none; +} + +.nav-stacked > li > a { + margin-right: 0; +} + +.nav-tabs.nav-stacked { + border-bottom: 0; +} + +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.nav-tabs.nav-stacked > li > a:hover { + z-index: 2; + border-color: #ddd; +} + +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} + +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} + +.nav-tabs .dropdown-menu { + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; +} + +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.nav-tabs .dropdown-toggle .caret, +.nav-pills .dropdown-toggle .caret { + margin-top: 6px; + border-top-color: #0088cc; + border-bottom-color: #0088cc; +} + +.nav-tabs .dropdown-toggle:hover .caret, +.nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; + border-bottom-color: #005580; +} + +.nav-tabs .active .dropdown-toggle .caret, +.nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; + border-bottom-color: #333333; +} + +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} + +.nav-tabs .open .dropdown-toggle, +.nav-pills .open .dropdown-toggle, +.nav > li.dropdown.open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} + +.nav li.dropdown.open .caret, +.nav li.dropdown.open.active .caret, +.nav li.dropdown.open a:hover .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} + +.tabs-stacked .open > a:hover { + border-color: #999999; +} + +.tabbable { + *zoom: 1; +} + +.tabbable:before, +.tabbable:after { + display: table; + content: ""; +} + +.tabbable:after { + clear: both; +} + +.tab-content { + overflow: auto; +} + +.tabs-below > .nav-tabs, +.tabs-right > .nav-tabs, +.tabs-left > .nav-tabs { + border-bottom: 0; +} + +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} + +.tab-content > .active, +.pill-content > .active { + display: block; +} + +.tabs-below > .nav-tabs { + border-top: 1px solid #ddd; +} + +.tabs-below > .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} + +.tabs-below > .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.tabs-below > .nav-tabs > li > a:hover { + border-top-color: #ddd; + border-bottom-color: transparent; +} + +.tabs-below > .nav-tabs > .active > a, +.tabs-below > .nav-tabs > .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} + +.tabs-left > .nav-tabs > li, +.tabs-right > .nav-tabs > li { + float: none; +} + +.tabs-left > .nav-tabs > li > a, +.tabs-right > .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} + +.tabs-left > .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} + +.tabs-left > .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.tabs-left > .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} + +.tabs-left > .nav-tabs .active > a, +.tabs-left > .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} + +.tabs-right > .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} + +.tabs-right > .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.tabs-right > .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} + +.tabs-right > .nav-tabs .active > a, +.tabs-right > .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} + +.navbar { + *position: relative; + *z-index: 2; + margin-bottom: 18px; + overflow: visible; +} + +.navbar-inner { + min-height: 40px; + + +} +/*Removed from .navbar-inner class above + padding-right: 20px; + padding-left: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +*/ + + +.navbar .container { + width: auto; +} + +.nav-collapse.collapse { + height: auto; +} + +.navbar { + color: #999999; +} + +.navbar .brand:hover { + text-decoration: none; +} + +.navbar .brand { + display: block; + float: left; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #999999; +} + +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; +} + +.navbar .navbar-link { + color: #999999; +} + +.navbar .navbar-link:hover { + color: #ffffff; +} + +.navbar .btn, +.navbar .btn-group { + margin-top: 5px; +} + +.navbar .btn-group .btn { + margin: 0; +} + +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} + +.navbar-form:before, +.navbar-form:after { + display: table; + content: ""; +} + +.navbar-form:after { + clear: both; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .radio, +.navbar-form .checkbox { + margin-top: 5px; +} + +.navbar-form input, +.navbar-form select { + display: inline-block; + margin-bottom: 0; +} + +.navbar-form input[type="image"], +.navbar-form input[type="checkbox"], +.navbar-form input[type="radio"] { + margin-top: 3px; +} + +.navbar-form .input-append, +.navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} + +.navbar-form .input-append input, +.navbar-form .input-prepend input { + margin-top: 0; +} + +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} + +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + background-color: #626262; + border: 1px solid #151515; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} + +.navbar-search .search-query:-moz-placeholder { + color: #aaa; +} + +.navbar-search .search-query:-ms-input-placeholder { + color: #cccccc; +} + +.navbar-search .search-query::-webkit-input-placeholder { + color: #cccccc; +} + +.navbar-search .search-query:focus, +.navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + outline: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); +} + +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; + margin-bottom: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-fixed-bottom .navbar-inner { + padding-right: 0; + padding-left: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.navbar-fixed-top { + top: 0; +} + +.navbar-fixed-bottom { + bottom: 0; +} + +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} + +.navbar .nav.pull-right { + float: right; +} + +.navbar .nav > li { + display: block; + float: left; +} + +.navbar .nav > li > a { + float: none; + padding: 9px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.navbar .btn { + display: inline-block; + padding: 4px 10px 4px; + margin: 5px 5px 6px; + line-height: 18px; +} + +.navbar .btn-group { + padding: 5px 5px 6px; + margin: 0; +} + +.navbar .nav > li > a:hover { + color: #ffffff; + text-decoration: none; + background-color: transparent; +} + +.navbar .nav .active > a, +.navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} + +.navbar .divider-vertical { + width: 1px; + height: 40px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} + +.navbar .nav.pull-right { + margin-right: 0; + margin-left: 10px; +} + +.navbar .btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-right: 5px; + margin-left: 5px; + background-color: #2677af; + *background-color: #2677af; + background-image: -ms-linear-gradient(top, #3989c2, #2677af); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#3989c2), to(#2677af)); + background-image: -webkit-linear-gradient(top, #3989c2, #2677af); + background-image: -o-linear-gradient(top, #3989c2, #2677af); + background-image: linear-gradient(top, #3989c2, #2677af); + background-image: -moz-linear-gradient(top, #3989c2, #2677af); + background-repeat: repeat-x; + border-color: #3989c2 #3989c2 #2677af; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#3989c2', endColorstr='#2677af', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} + +.navbar .btn-navbar:hover, +.navbar .btn-navbar:active, +.navbar .btn-navbar.active, +.navbar .btn-navbar.disabled, +.navbar .btn-navbar[disabled] { + background-color: #2677af; + *background-color: #2677af; +} + +.navbar .btn-navbar:active, +.navbar .btn-navbar.active { + background-color: #2677af \9; +} + +.navbar .btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} + +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} + +.navbar .dropdown-menu:before { + position: absolute; + top: -7px; + left: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} + +.navbar .dropdown-menu:after { + position: absolute; + top: -6px; + left: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + border-left: 6px solid transparent; + content: ''; +} + +.navbar-fixed-bottom .dropdown-menu:before { + top: auto; + bottom: -7px; + border-top: 7px solid #ccc; + border-bottom: 0; + border-top-color: rgba(0, 0, 0, 0.2); +} + +.navbar-fixed-bottom .dropdown-menu:after { + top: auto; + bottom: -6px; + border-top: 6px solid #ffffff; + border-bottom: 0; +} + +.navbar .nav li.dropdown .dropdown-toggle .caret, +.navbar .nav li.dropdown.open .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar .nav li.dropdown.active .caret { + opacity: 1; + filter: alpha(opacity=100); +} + +.navbar .nav li.dropdown.open > .dropdown-toggle, +.navbar .nav li.dropdown.active > .dropdown-toggle, +.navbar .nav li.dropdown.open.active > .dropdown-toggle { + background-color: transparent; +} + +.navbar .nav li.dropdown.active > .dropdown-toggle:hover { + color: #ffffff; +} + +.navbar .pull-right .dropdown-menu, +.navbar .dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.navbar .pull-right .dropdown-menu:before, +.navbar .dropdown-menu.pull-right:before { + right: 12px; + left: auto; +} + +.navbar .pull-right .dropdown-menu:after, +.navbar .dropdown-menu.pull-right:after { + right: 13px; + left: auto; +} + +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + list-style: none; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} + +.breadcrumb li { + display: inline-block; + *display: inline; + text-shadow: 0 1px 0 #ffffff; + *zoom: 1; +} + +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} + +.breadcrumb .active a { + color: #333333; +} + +.pagination { + height: 36px; + margin: 18px 0; +} + +.pagination ul { + display: inline-block; + *display: inline; + margin-bottom: 0; + margin-left: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + *zoom: 1; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.pagination li { + display: inline; +} + +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} + +.pagination a:hover, +.pagination .active a { + background-color: #f5f5f5; +} + +.pagination .active a { + color: #999999; + cursor: default; +} + +.pagination .disabled span, +.pagination .disabled a, +.pagination .disabled a:hover { + color: #999999; + cursor: default; + background-color: transparent; +} + +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.pagination-centered { + text-align: center; +} + +.pagination-right { + text-align: right; +} + +.pager { + margin-bottom: 18px; + margin-left: 0; + text-align: center; + list-style: none; + *zoom: 1; +} + +.pager:before, +.pager:after { + display: table; + content: ""; +} + +.pager:after { + clear: both; +} + +.pager li { + display: inline; +} + +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} + +.pager .next a { + float: right; +} + +.pager .previous a { + float: left; +} + +.pager .disabled a, +.pager .disabled a:hover { + color: #999999; + cursor: default; + background-color: #fff; +} + +.modal-open .dropdown-menu { + z-index: 2050; +} + +.modal-open .dropdown.open { + *z-index: 2050; +} + +.modal-open .popover { + z-index: 2060; +} + +.modal-open .tooltip { + z-index: 2070; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop, +.modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + width: 560px; + margin: -250px 0 0 -280px; + overflow: auto; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} + +.modal.fade { + top: -25%; + -webkit-transition: opacity 0.3s linear, top 0.3s ease-out; + -moz-transition: opacity 0.3s linear, top 0.3s ease-out; + -ms-transition: opacity 0.3s linear, top 0.3s ease-out; + -o-transition: opacity 0.3s linear, top 0.3s ease-out; + transition: opacity 0.3s linear, top 0.3s ease-out; +} + +.modal.fade.in { + top: 50%; +} + +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} + +.modal-header .close { + margin-top: 2px; +} + +.modal-body { + max-height: 400px; + padding: 15px; + overflow-y: auto; +} + +.modal-form { + margin-bottom: 0; +} + +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + text-align: right; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + content: ""; +} + +.modal-footer:after { + clear: both; +} + +.modal-footer .btn + .btn { + margin-bottom: 0; + margin-left: 5px; +} + +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} + +.tooltip { + position: absolute; + z-index: 1020; + display: block; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); + visibility: visible; +} + +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.tooltip.top { + margin-top: -2px; +} + +.tooltip.right { + margin-left: 2px; +} + +.tooltip.bottom { + margin-top: 2px; +} + +.tooltip.left { + margin-left: -2px; +} + +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-top: 5px solid #000000; + border-right: 5px solid transparent; + border-left: 5px solid transparent; +} + +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} + +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; + border-left: 5px solid transparent; +} + +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-right: 5px solid #000000; + border-bottom: 5px solid transparent; +} + +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} + +.popover.top { + margin-top: -5px; +} + +.popover.right { + margin-left: 5px; +} + +.popover.bottom { + margin-top: 5px; +} + +.popover.left { + margin-left: -5px; +} + +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-top: 5px solid #000000; + border-right: 5px solid transparent; + border-left: 5px solid transparent; +} + +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-right: 5px solid #000000; + border-bottom: 5px solid transparent; +} + +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; + border-left: 5px solid transparent; +} + +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} + +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} + +.popover-inner { + width: 280px; + padding: 3px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} + +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} + +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} + +.popover-content p, +.popover-content ul, +.popover-content ol { + margin-bottom: 0; +} + +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} + +.thumbnails:before, +.thumbnails:after { + display: table; + content: ""; +} + +.thumbnails:after { + clear: both; +} + +.row-fluid .thumbnails { + margin-left: 0; +} + +.thumbnails > li { + float: left; + margin-bottom: 18px; + margin-left: 20px; +} + +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} + +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} + +.thumbnail > img { + display: block; + max-width: 100%; + margin-right: auto; + margin-left: auto; +} + +.thumbnail .caption { + padding: 9px; +} + +.label, +.badge { + font-size: 10.998px; + font-weight: bold; + line-height: 14px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + white-space: nowrap; + vertical-align: baseline; + background-color: #999999; +} + +.label { + padding: 1px 4px 2px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.badge { + padding: 1px 9px 2px; + -webkit-border-radius: 9px; + -moz-border-radius: 9px; + border-radius: 9px; +} + +a.label:hover, +a.badge:hover { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +.label-important, +.badge-important { + background-color: #b94a48; +} + +.label-important[href], +.badge-important[href] { + background-color: #953b39; +} + +.label-warning, +.badge-warning { + background-color: #f89406; +} + +.label-warning[href], +.badge-warning[href] { + background-color: #c67605; +} + +.label-success, +.badge-success { + background-color: #468847; +} + +.label-success[href], +.badge-success[href] { + background-color: #356635; +} + +.label-info, +.badge-info { + background-color: #3a87ad; +} + +.label-info[href], +.badge-info[href] { + background-color: #2d6987; +} + +.label-inverse, +.badge-inverse { + background-color: #333333; +} + +.label-inverse[href], +.badge-inverse[href] { + background-color: #1a1a1a; +} + +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-moz-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-ms-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-o-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} + +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +.progress { + height: 18px; + margin-bottom: 18px; + overflow: hidden; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.progress .bar { + width: 0; + height: 18px; + font-size: 12px; + color: #ffffff; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} + +.progress-striped .bar { + background-color: #149bdf; + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} + +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} + +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} + +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} + +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-warning .bar { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); +} + +.progress-warning.progress-striped .bar { + background-color: #fbb450; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.accordion { + margin-bottom: 18px; +} + +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.accordion-heading { + border-bottom: 0; +} + +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} + +.accordion-toggle { + cursor: pointer; +} + +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} + +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel .item { + position: relative; + display: none; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} + +.carousel .item > img { + display: block; + line-height: 1; +} + +.carousel .active, +.carousel .next, +.carousel .prev { + display: block; +} + +.carousel .active { + left: 0; +} + +.carousel .next, +.carousel .prev { + position: absolute; + top: 0; + width: 100%; +} + +.carousel .next { + left: 100%; +} + +.carousel .prev { + left: -100%; +} + +.carousel .next.left, +.carousel .prev.right { + left: 0; +} + +.carousel .active.left { + left: -100%; +} + +.carousel .active.right { + left: 100%; +} + +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} + +.carousel-control.right { + right: 15px; + left: auto; +} + +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} + +.carousel-caption { + position: absolute; + right: 0; + bottom: 0; + left: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} + +.carousel-caption h4, +.carousel-caption p { + color: #ffffff; +} + +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #eeeeee; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; + color: inherit; +} + +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; + color: inherit; +} + +.pull-right { + float: right; +} + +.pull-left { + float: left; +} + +.hide { + display: none; +} + +.show { + display: block; +} + +.invisible { + visibility: hidden; +} diff --git a/src/alloy/Static/css/editmode.css b/src/alloy/Static/css/editmode.css new file mode 100644 index 0000000..55318c8 --- /dev/null +++ b/src/alloy/Static/css/editmode.css @@ -0,0 +1,33 @@ +/* CSS specific to edit mode, such as help content displayed to the editor */ + +.alert-info +{ + border-color: #B8C0C5; + color: black; + font-family: Verdana; + font-size: 1em; + font-style: italic; + background-color: #B8C0C5; + box-shadow: 3px 3px 5px #CCC; + text-align: center; + } + +.alert-error p { + text-align: left; +} + +.alert-error .heading { + font-weight: bold; + color: #ff0000; +} + +.alert-error .details { + font-size: 0.8em; + max-height: 100px; + overflow: scroll; +} + +.header.dim { + margin: 2% 0; + opacity: 0.3; +} \ No newline at end of file diff --git a/src/alloy/Static/css/editor.css b/src/alloy/Static/css/editor.css new file mode 100644 index 0000000..0b2e4ff --- /dev/null +++ b/src/alloy/Static/css/editor.css @@ -0,0 +1,2 @@ +@import "bootstrap.css"; +@import "style.css"; diff --git a/src/alloy/Static/css/media.css b/src/alloy/Static/css/media.css new file mode 100644 index 0000000..0431dd2 --- /dev/null +++ b/src/alloy/Static/css/media.css @@ -0,0 +1,145 @@ +@charset "utf-8"; +/* CSS Document */ + + + +@media (max-width: 979px) { +.span12, .span8, .span6, .span4 { + float: none; + width: auto !important; + } + +.span4 h2, .span6 h2 +{ + clear:both; + } + +.teaserblock.full h2, .teaserblock.wide h2 { + font-size: 2.5em; +} + +.subHeader +{ + width:100% !important; + font-weight:normal !important; + } + +.jumbotronblock .span4 +{ + display:none; + } + +.media .mediaImg img +{ + width:75%;} + + +.hideMyTracks {display:none;} + +} + + + +@media (max-width: 834px) { + +.teaserblock.full h2, .teaserblock.wide h2 { + clear:both; +} + +.teaserblock.full h2, .teaserblock.wide h2, .teaserblock.full p, .teaserblock.wide p { + text-align:center; +} + +.teaserblock.full img, .teaserblock.wide img { + width:75%; +} + +#header .span2 +{ + float:left; + width:20% !important; + } + +#header .span10 +{ + float:right; + } + +.span12 .media .mediaText, .span8 .media .mediaText +{ + clear:both; + margin:0 2% 5px; + } + +} + +@media (max-width: 767px) { + +h1 +{ + font-size:35px !important; + } + +h2 +{ + font-size:20px !important; + } + +.introduction { + font-size:1.2em !important; + margin:2% 0 4% 0; + } + +.alloyMenu .navbar .nav>li>a { + color:#323335; + padding-bottom:12px; + line-height:23px; + text-shadow:none !important; + outline:none; + } + +.alloyMenu .navbar .nav>li>ul>li a:hover { + outline:1px solid; + background:#2980bd; + } + + +.span3 { + width:100% !important; + + } + +.teaserblock img { + width:75%; + } + +.btn-blue { + margin-right:1%; + float:left; + clear:none; + } + +.searchButton { + float:right; + margin-top:7px !important; + } + +.alloyMenu .navbar-search .search-query +{ + max-width:70%; + } + + +#header .span2 +{ + float:left; + width:20% !important; + } + +#header .span10 +{ + float:right; + } + +} + diff --git a/src/alloy/Static/css/style.css b/src/alloy/Static/css/style.css new file mode 100644 index 0000000..4056016 --- /dev/null +++ b/src/alloy/Static/css/style.css @@ -0,0 +1,639 @@ +@charset "utf-8"; +/* CSS Document */ + +/*Headers*/ + +#header { + margin:2% 0; + } + + +/*General*/ + + +h1 { + font-family:verdana; + font-size:4.5em; + line-height:1.1em; + } + +h1.jumbotron { + font-family:verdana; + font-size:4.5em; + line-height:1.1em; + margin-top:4%; + word-wrap:break-word; + } + +.subHeader { + font-family:verdana; + font-size:1.5em; + font-weight:bold; + line-height:1.3em; + margin:2% 0 4% 0; + width:80%; + } + +.introduction { + font-family:verdana; + font-size:1.4em; + font-weight:bold; + line-height:1.3em; + margin:2% 0 2% 0; + } + +p { + font-size:1.1em; + } + +a { + outline:none; + } + +ul { + font-size:1.1em; + } + +.share { + margin:4% 0; + } + +.right { + float:right !important; + } + +/*Top*/ + + +.logotype { + margin:2% 0; + } + + +/*Search page*/ + +.grayHead { + border-radius:4px; + background:#f1f1f1; + margin-bottom:2%; + } + +.grayHead h2, .grayHead p { + margin:1%; + } + +.btnCheckbox { + -moz-border-bottom-colors: none; + -moz-border-left-colors: none; + -moz-border-right-colors: none; + -moz-border-top-colors: none; + background-color: #F5F5F5; + background-image: -moz-linear-gradient(center top , #FFFFFF, #E6E6E6); + background-repeat: repeat-x; + border-color: #E6E6E6 #E6E6E6 #A2A2A2; + border-image: none; + border-radius: 4px 4px 4px 4px; + border-style: solid; + border-width: 1px; + box-shadow: 0 1px 0 rgba(255, 255, 255, 0.2) inset, 0 1px 2px rgba(0, 0, 0, 0.05); + color: #333333; + cursor: pointer; + display: inline-block; + font-size: 14px; + line-height: 20px; + margin-bottom: 0; + padding: 4px 14px; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; +} + +.btn-primary:hover, .btn-group .btnCheckbox, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0055cc; + *background-color: #004ab3; +} + +.SearchResults img, .listResult img { + float:left; + margin-bottom:1%; + margin-right:2%; + } + +.listResult h3 +{ + font-size:1.3em; + } + +.SearchResults hr, .listResult hr { + width:100%; + clear:both; + margin:2% 0; + } + +/*Content*/ + +.row { + margin-bottom:1%; + } + +.span2, .span3, .span4, .span5, .span6, .span7, .span8, .span9, .span10, .span11, .span12 +{ + margin-bottom:2%; + } + +.text-center { + text-align: center; +} + +#header .span2, #header .span10 +{ + margin-bottom:0px; + } + +.date { + font-size:0.8em; + margin-top:-9px; + } + +.pagelistblock div { + padding-left:5px; +} + +.pagelistblock .theme1 { + border-left:2px solid #EB5E31; + } + +.pagelistblock .theme2 { + border-left:2px solid #BF5D8C; + } + +.pagelistblock .theme3 { + border-left:2px solid #9FC733; + } + +.quotePuff { + height:250px; + } + +.quotePuff h3 { + margin:22% 10%; + text-align:center; + } + + + +.field-validation-error +{ + display: block; + color: #b94a48; +} + +.equal-height .teaserblock .border { + min-height: 245px; +} + +.teaserblock { + text-align:center; +} + +.teaserblock.full img, .teaserblock.wide img { + float:left; + margin-right:30px; + max-width:375px; + overflow:hidden; + } + +.teaserblock.full h2, .teaserblock.full p, .teaserblock.wide h2, .teaserblock.wide p { + text-align:left; + margin:0 10px 10px 0; + } + +.teaserblock.full p, .teaserblock.wide p { + font-size:1.3em; + } + +.teaserblock.full h2, .teaserblock.wide h2 { + margin:10px 10px 10px 0; + font-size:3em; + } + + +.teaserblock p { + width:96%; + margin-left:2%; + } + +.border { + border-radius:4px; + border:1px solid #d6d6d6; + text-align:center; + overflow:hidden; + } + +.border p { + width:96%; + margin-left:2%; + } + +.teaserblock h2, .teaserblock p, a h2, a p +{ + color:#333; + } + +.border a:hover h2 +{ + text-decoration:underline !important; + } + +.teaserblock a, .teaserblock a:hover, .teaserblock.full a, .teaserblock.full a:hover, .teaserblock.half a, .teaserblock.half a:hover, .teaserblock.wide a, .teaserblock.wide a:hover { + color:#333; + } + +.teaserblock h2, .teaserblock p +{ + text-align:center; + margin-left:1%; + width:98%; + } + +.colorBox { + border-radius:4px; + margin:10px 0; + padding-bottom:3px; + background:#bdbdbd; + background-image:-moz-linear-gradient(center top , #d9d9d9, #bdbdbd); + color:#333; + } + +.block.theme1 { + background:#eb5e31; + background-image:-moz-linear-gradient(center top , #eb8931, #eb5e31); + color:#fff; + } + +.block.theme2 { + background:#bf5d8c; + background-image:-moz-linear-gradient(center top , #db5a98, #bf5d8c); + color:#fff; + } + +.block.theme3 { + background:#9fc733; + background-image:-moz-linear-gradient(center top , #b1e031, #9fc733); + color:#fff; + } + +.colorBox ul { + list-style-type:none; + margin:0 0 2% 3%; + } + +.colorBox a, .colorBox a:hover { + color:#333; + } + +.block.theme1 a, .block.theme1 a:hover, .block.theme2 a, .block.theme2 a:hover, .block.theme3 a, .block.theme3 a:hover { + color:#fff; + } + +.colorBox h2, .colorBox p { + margin:1% 3%; + } + +.formContainer p { + margin-bottom:4px; + margin-top:4px; + } + +/* ====== media ====== */ +.media {margin:10px; margin-left:0px;} +.media, .mediaText {overflow:hidden; _overflow:visible; zoom:1;} +.media .mediaImg {float:left; margin-right: 30px;} +.media .mediaImg img{display:block; max-width:370px;} + +.span8 .media .mediaImg img{max-width:300px; margin-right:15px;} + +.media p { + font-size:1.3em; + } + +.media h2 { + font-size:3em; + margin:10px 0; + } + +/*Buttons*/ + +.btn-blue { + width:100%; + max-width:170px; + height:50px; + border-radius:4px; + background:#2677af; + background-image:-moz-linear-gradient(center top , #3989c2, #2677af); + color:#fff; + display: inline-block; + text-align:center; + line-height:50px; + font-size:1.2em; + letter-spacing:0.5px; + margin-bottom:10px; + clear:both; + font-weight:bold; + } + +.btn-blue:hover { + background:#4b8ab7; + background-image:-moz-linear-gradient(center top , #5f9eca, #4b8ab7); + text-decoration:none; + color:#fff; + } + +/*Image*/ +.image-file { + width: 100%; +} + +/*Video*/ + +.embed { + position: relative; + padding-bottom: 56.25%; + height: 0; + overflow: hidden; +} + +.embed iframe, .embed object, .embed embed, .embed video { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +/*Footer*/ + +.footer ul { + list-style-type:none; + margin:1% 0; + } + +/*Fixes*/ + +.setMargins div.span4 { + margin-bottom:20px; + } + + + +/*Alloy Menu*/ + +.alloyMenu { + color:#323335; + letter-spacing:0.1px; + font-family:verdana; + text-shadow:none !important; + margin-top:3%; + margin-bottom: 18px; + } + +.alloyMenu .navbar-inner { + background:#fff; + color:#323335; + text-shadow:none !important; + box-shadow:none; + } + +.alloyMenu .navbar .nav>li>a { + color:#323335; + padding-bottom:12px; + line-height:23px; + text-shadow:none !important; + outline:none; + } + +.alloyMenu .navbar .nav>li>a:hover { + background:#fff; + text-shadow:none !important; + color:#2980bd; + border-bottom:1px solid #2980bd; + } + +.alloyMenu .navbar .nav>li>a.theme1:hover { + background:#fff; + text-shadow:none !important; + color:#EB5E31; + border-bottom:1px solid #EB5E31; + } + +.alloyMenu .navbar .nav>li>a.theme3:hover { + background:#fff; + text-shadow:none !important; + color:#9FC733; + border-bottom:1px solid #9FC733; + } + +.alloyMenu .navbar .nav>li>a.theme2:hover { + background:#fff; + text-shadow:none !important; + color:#BF5D8C; + border-bottom:1px solid #BF5D8C; + } + +.alloyMenu .navbar .nav>li.active>a { + background:#fff; + text-shadow:none !important; + color:#2980bd; + border-bottom:1px solid #2980bd; + } + +.alloyMenu .navbar .nav>li.active>a.theme1 { + background:#fff; + text-shadow:none !important; + color:#EB5E31; + border-bottom:1px solid #EB5E31; + } + +.alloyMenu .navbar .nav>li.active>a.theme3 { + background:#fff; + text-shadow:none !important; + color:#9FC733; + border-bottom:1px solid #9FC733; + } + +.alloyMenu .navbar .nav>li.active>a.theme2 { + background:#fff; + text-shadow:none !important; + color:#BF5D8C; + border-bottom:1px solid #BF5D8C; + } + +.alloyMenu .navbar ul { + font-size:1em; + } + +.alloyMenu .caret { + opacity:0.9; + color:#323335; + border-top-color:#323335 !important; + border-bottom-color:#323335 !important; + } + +.alloyMenu .navbar-search .search-query { + padding: 4px 5px 4px 13px; + text-shadow:none; + background:#fff; + margin-bottom:0; + border-color:#d9d9d9; + box-shadow:none; + } + +form.navbar-search { + background:#d6d6d6; + border:1px solid #d6d6d6; + border-radius:4px; + padding: 4px 5px; + margin-top:0; + } + +.alloyMenu .navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 4px 5px 4px 13px; + text-shadow:none; + border:1px solid #d9d9d9; + color:#aaa; + } + +.search-query +{ + margin-bottom:0px !important; + margin-top:7px; + width:200px; + color:#aaa; + } + +.searchButton { + height:28px !important; + width:28px !important; + background:url(../gfx/searchbuttonsmall.png) no-repeat top left !important; + border:none !important; + margin-top:7px !important; + } + +/*Alloy side navigation*/ + +#alloyDrop .accordion-group { + border:1px solid #ddd; + } + +#alloyDrop .accordion-group li { + line-height:40px; + } + +#alloyDrop .accordion-group .accordion-heading { + background:#fff; + font-weight:bold; + } + +#alloyDrop .accordion-group .accordion-heading a.accordion-toggle { + color:#323335; + outline:none; + } + +#alloyDrop .accordion-group ul { + margin:5px 0; + background:#fff; + list-style-type:none; + + } + +#alloyDrop .accordion-group ul ol, #alloyDrop .accordion-group ul ul { + margin:5px 0 0 0; + background:#fff; + list-style-type:none; + } + +#alloyDrop .accordion-group ul li { + width:100%; + } + +#alloyDrop .accordion-group ul li .icon-chevron-down { + margin-top:10px; + margin-right:15px; + } + + +#alloyDrop .accordion-group ul li a { + padding-left:30px; + width:100%; + color:#333; + } + +#alloyDrop .accordion-group ul li a:hover { + color: #2980BD !important; + } + +#alloyDrop .accordion-group ul li ol { + padding-left:0px; + background:#fff; + } + +#alloyDrop .accordion-group ul ol li, #alloyDrop .accordion-group ul ul li { + border-bottom:0px solid #d6d6d6; + border-top:1px solid #d6d6d6; + } + +#alloyDrop .accordion-group ul ol li a, #alloyDrop .accordion-group ul ul li a { + padding-left:50px; + } + +#alloyDrop a.active +{ + background: none repeat scroll 0 0 #2980BD; + color: #FFFFFF !important; + } + +/*Campaign*/ + +.campaign-wrapper +{ + margin:5% 0; + } + +/*Alloy Breadcrumb*/ + +.alloyBreadcrumb { + background:none; + list-style-type:none; + margin:0 0 -20px 0; + padding:7px 14px; + } + +.alloyBreadcrumb li { + display:inline; + } + +.alloyBreadcrumb .divider { + color:#999; + padding:0 5px; + } + +.thankyoumessage { + padding: 1em 0.5em; + margin: 0; + font-weight: bold; + } + +/* Search page */ +form.search-form { + margin-bottom: 0; +} + +/* Edit container style */ +.epi-editContainer { + min-height: 1.1em; + min-width: 1.6em; +} diff --git a/src/alloy/Static/gfx/New_FDT_Press_Contact_.JPG b/src/alloy/Static/gfx/New_FDT_Press_Contact_.JPG new file mode 100644 index 0000000..70450a9 Binary files /dev/null and b/src/alloy/Static/gfx/New_FDT_Press_Contact_.JPG differ diff --git a/src/alloy/Static/gfx/carouselbackground.png b/src/alloy/Static/gfx/carouselbackground.png new file mode 100644 index 0000000..2c6f912 Binary files /dev/null and b/src/alloy/Static/gfx/carouselbackground.png differ diff --git a/src/alloy/Static/gfx/contact.jpg b/src/alloy/Static/gfx/contact.jpg new file mode 100644 index 0000000..0ad79ee Binary files /dev/null and b/src/alloy/Static/gfx/contact.jpg differ diff --git a/src/alloy/Static/gfx/exampelspan4.png b/src/alloy/Static/gfx/exampelspan4.png new file mode 100644 index 0000000..6ddff68 Binary files /dev/null and b/src/alloy/Static/gfx/exampelspan4.png differ diff --git a/src/alloy/Static/gfx/experts.png b/src/alloy/Static/gfx/experts.png new file mode 100644 index 0000000..e8439ee Binary files /dev/null and b/src/alloy/Static/gfx/experts.png differ diff --git a/src/alloy/Static/gfx/fallows-media-wide.jpg b/src/alloy/Static/gfx/fallows-media-wide.jpg new file mode 100644 index 0000000..ea6374b Binary files /dev/null and b/src/alloy/Static/gfx/fallows-media-wide.jpg differ diff --git a/src/alloy/Static/gfx/leader.png b/src/alloy/Static/gfx/leader.png new file mode 100644 index 0000000..7ac2b56 Binary files /dev/null and b/src/alloy/Static/gfx/leader.png differ diff --git a/src/alloy/Static/gfx/leader2.png b/src/alloy/Static/gfx/leader2.png new file mode 100644 index 0000000..9016088 Binary files /dev/null and b/src/alloy/Static/gfx/leader2.png differ diff --git a/src/alloy/Static/gfx/logotype.png b/src/alloy/Static/gfx/logotype.png new file mode 100644 index 0000000..4b786f7 Binary files /dev/null and b/src/alloy/Static/gfx/logotype.png differ diff --git a/src/alloy/Static/gfx/meet.jpg b/src/alloy/Static/gfx/meet.jpg new file mode 100644 index 0000000..a063b0c Binary files /dev/null and b/src/alloy/Static/gfx/meet.jpg differ diff --git a/src/alloy/Static/gfx/page-type-thumbnail-article.png b/src/alloy/Static/gfx/page-type-thumbnail-article.png new file mode 100644 index 0000000..236f213 Binary files /dev/null and b/src/alloy/Static/gfx/page-type-thumbnail-article.png differ diff --git a/src/alloy/Static/gfx/page-type-thumbnail-contact.png b/src/alloy/Static/gfx/page-type-thumbnail-contact.png new file mode 100644 index 0000000..23d7728 Binary files /dev/null and b/src/alloy/Static/gfx/page-type-thumbnail-contact.png differ diff --git a/src/alloy/Static/gfx/page-type-thumbnail-product.png b/src/alloy/Static/gfx/page-type-thumbnail-product.png new file mode 100644 index 0000000..f5d4fb6 Binary files /dev/null and b/src/alloy/Static/gfx/page-type-thumbnail-product.png differ diff --git a/src/alloy/Static/gfx/page-type-thumbnail-standard.png b/src/alloy/Static/gfx/page-type-thumbnail-standard.png new file mode 100644 index 0000000..0f1ccff Binary files /dev/null and b/src/alloy/Static/gfx/page-type-thumbnail-standard.png differ diff --git a/src/alloy/Static/gfx/page-type-thumbnail.png b/src/alloy/Static/gfx/page-type-thumbnail.png new file mode 100644 index 0000000..96a574a Binary files /dev/null and b/src/alloy/Static/gfx/page-type-thumbnail.png differ diff --git a/src/alloy/Static/gfx/person.png b/src/alloy/Static/gfx/person.png new file mode 100644 index 0000000..ef69dc5 Binary files /dev/null and b/src/alloy/Static/gfx/person.png differ diff --git a/src/alloy/Static/gfx/plan.jpg b/src/alloy/Static/gfx/plan.jpg new file mode 100644 index 0000000..bf00d05 Binary files /dev/null and b/src/alloy/Static/gfx/plan.jpg differ diff --git a/src/alloy/Static/gfx/play.png b/src/alloy/Static/gfx/play.png new file mode 100644 index 0000000..e12b279 Binary files /dev/null and b/src/alloy/Static/gfx/play.png differ diff --git a/src/alloy/Static/gfx/playInactive.png b/src/alloy/Static/gfx/playInactive.png new file mode 100644 index 0000000..a5bc660 Binary files /dev/null and b/src/alloy/Static/gfx/playInactive.png differ diff --git a/src/alloy/Static/gfx/productLandingv2.png b/src/alloy/Static/gfx/productLandingv2.png new file mode 100644 index 0000000..1c8bc9a Binary files /dev/null and b/src/alloy/Static/gfx/productLandingv2.png differ diff --git a/src/alloy/Static/gfx/searchbutton.png b/src/alloy/Static/gfx/searchbutton.png new file mode 100644 index 0000000..eb5dc48 Binary files /dev/null and b/src/alloy/Static/gfx/searchbutton.png differ diff --git a/src/alloy/Static/gfx/searchbuttonsmall.png b/src/alloy/Static/gfx/searchbuttonsmall.png new file mode 100644 index 0000000..96665b2 Binary files /dev/null and b/src/alloy/Static/gfx/searchbuttonsmall.png differ diff --git a/src/alloy/Static/gfx/track.jpg b/src/alloy/Static/gfx/track.jpg new file mode 100644 index 0000000..2682bdf Binary files /dev/null and b/src/alloy/Static/gfx/track.jpg differ diff --git a/src/alloy/Static/html/error.htm b/src/alloy/Static/html/error.htm new file mode 100644 index 0000000..298e5dd --- /dev/null +++ b/src/alloy/Static/html/error.htm @@ -0,0 +1,13 @@ + + + An error occured + + + + Logotype +

When things go wrong...

+

This error message can be modified by editing the /Static/html/error.htm file.

+ + diff --git a/src/alloy/Static/img/glyphicons-halflings-white.png b/src/alloy/Static/img/glyphicons-halflings-white.png new file mode 100644 index 0000000..3bf6484 Binary files /dev/null and b/src/alloy/Static/img/glyphicons-halflings-white.png differ diff --git a/src/alloy/Static/img/glyphicons-halflings.png b/src/alloy/Static/img/glyphicons-halflings.png new file mode 100644 index 0000000..79bc568 Binary files /dev/null and b/src/alloy/Static/img/glyphicons-halflings.png differ diff --git a/src/alloy/Static/js/bootstrap.js b/src/alloy/Static/js/bootstrap.js new file mode 100644 index 0000000..d5a9cfc --- /dev/null +++ b/src/alloy/Static/js/bootstrap.js @@ -0,0 +1,1806 @@ + +!function ($) { + + $(function () { + + "use strict"; // jshint ;_; + + + /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) + * ======================================================= */ + + $.support.transition = (function () { + + var transitionEnd = (function () { + + var el = document.createElement('bootstrap') + , transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd' + , 'MozTransition' : 'transitionend' + , 'OTransition' : 'oTransitionEnd' + , 'msTransition' : 'MSTransitionEnd' + , 'transition' : 'transitionend' + } + , name + + for (name in transEndEventNames){ + if (el.style[name] !== undefined) { + return transEndEventNames[name] + } + } + + }()) + + return transitionEnd && { + end: transitionEnd + } + + })() + + }) + +}(window.jQuery);/* ========================================================== + * bootstrap-alert.js v2.0.4 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent.trigger(e = $.Event('close')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}(window.jQuery);/* ============================================================ + * bootstrap-button.js v2.0.4 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + Button.prototype.toggle = function () { + var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}(window.jQuery);/* ========================================================== + * bootstrap-carousel.js v2.0.4 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = options + this.options.slide && this.slide(this.options.slide) + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.prototype = { + + cycle: function (e) { + if (!e) this.paused = false + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function (e) { + if (!e) this.paused = true + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + , e = $.Event('slide') + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + if ($next.hasClass('active')) return + + if ($.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } else { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option) + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (typeof option == 'string' || (option = options.slide)) data[option]() + else if (options.interval) data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + , pause: 'hover' + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL DATA-API + * ================= */ + + $(function () { + $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + }) + +}(window.jQuery);/* ============================================================= + * bootstrap-collapse.js v2.0.4 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* COLLAPSE PUBLIC CLASS DEFINITION + * ================================ */ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options.parent) { + this.$parent = $(this.options.parent) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension + , scroll + , actives + , hasData + + if (this.transitioning) return + + dimension = this.dimension() + scroll = $.camelCase(['scroll', dimension].join('-')) + actives = this.$parent && this.$parent.find('> .accordion-group > .in') + + if (actives && actives.length) { + hasData = actives.data('collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', $.Event('show'), 'shown') + this.$element[dimension](this.$element[0][scroll]) + } + + , hide: function () { + var dimension + if (this.transitioning) return + dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', $.Event('hide'), 'hidden') + this.$element[dimension](0) + } + + , reset: function (size) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') + + return this + } + + , transition: function (method, startEvent, completeEvent) { + var that = this + , complete = function () { + if (startEvent.type == 'show') that.reset() + that.transitioning = 0 + that.$element.trigger(completeEvent) + } + + this.$element.trigger(startEvent) + + if (startEvent.isDefaultPrevented()) return + + this.transitioning = 1 + + this.$element[method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + + /* COLLAPSIBLE PLUGIN DEFINITION + * ============================== */ + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSIBLE DATA-API + * ==================== */ + + $(function () { + $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $(target).collapse(option) + }) + }) + +}(window.jQuery);/* ============================================================ + * bootstrap-dropdown.js v2.0.4 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle="dropdown"]' + , Dropdown = function (element) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function (e) { + var $this = $(this) + , $parent + , selector + , isActive + + if ($this.is('.disabled, :disabled')) return + + selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) $parent.toggleClass('open') + + return false + } + + } + + function clearMenus() { + $(toggle).parent().removeClass('open') + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(function () { + $('html').on('click.dropdown.data-api', clearMenus) + $('body') + .on('click.dropdown', '.dropdown form', function (e) { e.stopPropagation() }) + .on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) + }) + +}(window.jQuery);/* ========================================================= + * bootstrap-modal.js v2.0.4 + * http://twitter.github.com/bootstrap/javascript.html#modals + * ========================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* MODAL CLASS DEFINITION + * ====================== */ + + var Modal = function (content, options) { + this.options = options + this.$element = $(content) + .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) + } + + Modal.prototype = { + + constructor: Modal + + , toggle: function () { + return this[!this.isShown ? 'show' : 'hide']() + } + + , show: function () { + var that = this + , e = $.Event('show') + + this.$element.trigger(e) + + if (this.isShown || e.isDefaultPrevented()) return + + $('body').addClass('modal-open') + + this.isShown = true + + escape.call(this) + backdrop.call(this, function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + if (!that.$element.parent().length) { + that.$element.appendTo(document.body) //don't move modals dom position + } + + that.$element + .show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element.addClass('in') + + transition ? + that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : + that.$element.trigger('shown') + + }) + } + + , hide: function (e) { + e && e.preventDefault() + + var that = this + + e = $.Event('hide') + + this.$element.trigger(e) + + if (!this.isShown || e.isDefaultPrevented()) return + + this.isShown = false + + $('body').removeClass('modal-open') + + escape.call(this) + + this.$element.removeClass('in') + + $.support.transition && this.$element.hasClass('fade') ? + hideWithTransition.call(this) : + hideModal.call(this) + } + + } + + + /* MODAL PRIVATE METHODS + * ===================== */ + + function hideWithTransition() { + var that = this + , timeout = setTimeout(function () { + that.$element.off($.support.transition.end) + hideModal.call(that) + }, 500) + + this.$element.one($.support.transition.end, function () { + clearTimeout(timeout) + hideModal.call(that) + }) + } + + function hideModal(that) { + this.$element + .hide() + .trigger('hidden') + + backdrop.call(this) + } + + function backdrop(callback) { + var that = this + , animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $('