├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .nuget ├── NuGet.Config ├── NuGet.exe └── NuGet.targets ├── LICENSE.md ├── NuGet.Config ├── PowerSlice.sln ├── PowerSlice ├── ContentSliceBase.cs ├── ContentSliceComponent.cs ├── CreateOption.cs ├── IContentSlice.cs ├── ISortableContentSlice.cs ├── InitializationModule.cs ├── PowerSlice.csproj ├── PowerSlice.nuspec ├── SlicesComponent.cs ├── SortAction.cs ├── SortOption.cs ├── clientResources │ ├── PowerSlice │ │ └── Components │ │ │ ├── ContentSlice.js │ │ │ ├── ContentSliceGrid.js │ │ │ ├── CreateContentInSliceDialog.js │ │ │ ├── CreateSpecificContent.js │ │ │ ├── SortDropDown.js │ │ │ ├── Tasks.js │ │ │ └── templates │ │ │ ├── CreateContentInSliceDialog.html │ │ │ └── Tasks.html │ ├── css │ │ ├── powerslice.css │ │ ├── powerslice.css.map │ │ └── powerslice.less │ └── images │ │ ├── commonFormArrows.png │ │ ├── sortAscending.png │ │ ├── sortDescending.png │ │ └── sorticon.png ├── lang │ └── PowerSlice.xml ├── module.config ├── modules │ └── _protected │ │ └── Find │ │ └── Find.zip ├── version.props └── web.config.transform ├── README.md ├── assets └── readme.txt ├── build ├── CopyZipFiles.targets ├── DependencyVersions.props ├── get-version.ps1 ├── license.targets ├── licenses │ ├── LICENSE.txt.template │ ├── NO-THIRD-PARTY-LICENSES.txt │ └── default-license-texts │ │ ├── Apache-2.0.txt │ │ ├── ISC.txt │ │ ├── MIT.txt │ │ ├── Ms-PL.txt │ │ └── README ├── nuspec.props ├── pack.ps1 ├── tasks │ ├── extract.js │ └── unit-tests.js └── test.props ├── pack.bat └── sample └── AlloyMvcTemplates ├── .gitignore ├── AlloyMvcTemplates.csproj ├── Business ├── Channels │ ├── DisplayResolutionBase.cs │ ├── DisplayResolutions.cs │ ├── MobileChannel.cs │ └── WebChannel.cs ├── ContentExtensions.cs ├── ContentLocator.cs ├── EditorDescriptors │ ├── ContactPageSelectionFactory.cs │ └── ContactPageSelector.cs ├── IModifyLayout.cs ├── Initialization │ └── CustomizedRenderingInitialization.cs ├── PageContextActionFilter.cs ├── PageTypeExtensions.cs ├── PageViewContextFactory.cs ├── Plugins │ └── NewsGeneratorPlugin.cs ├── Rendering │ ├── AlloyContentAreaRenderer.cs │ ├── ErrorHandlingContentRenderer.cs │ ├── IContainerPage.cs │ ├── ICustomCssInContentArea.cs │ ├── SiteViewEngineLocationExpander.cs │ └── TemplateCoordinator.cs └── UIDescriptors │ └── ContainerPageUIDescriptor.cs ├── ClientResources ├── Images │ └── icons │ │ ├── editing.png │ │ └── layoutIcons24x24.png ├── Scripts │ └── Editors │ │ └── StringList.js └── Styles │ └── Styles.css ├── Components ├── ContactBlockViewComponent.cs ├── ImageFileViewComponent.cs ├── PageListBlockViewComponent.cs └── VideoFileViewComponent.cs ├── Controllers ├── DefaultPageController.cs ├── PageControllerBase.cs ├── PreviewController.cs ├── RegisterController.cs ├── RouteAttributeController.cs ├── SearchPageController.cs └── StartPageController.cs ├── CustomPowerSlice ├── ArticleSlice.cs ├── BlocksSlice.cs ├── EverythingSlice.cs ├── MyPagesSlice.cs └── PagesSlice.cs ├── Extensions ├── HttpContextExtensions.cs ├── ServiceCollectionExtensions.cs └── ViewContextExtension.cs ├── Global.cs ├── Helpers ├── CategorizableExtensions.cs ├── HtmlHelpers.cs └── UrlHelpers.cs ├── Infrastructure ├── AdministratorRegistrationPageMiddleware.cs └── RegisterFirstAdminWithLocalRequestAttribute.cs ├── InternalServiceCollectionExtensions.cs ├── Models ├── Blocks │ ├── ButtonBlock.cs │ ├── ContactBlock.cs │ ├── EditorialBlock.cs │ ├── JumbotronBlock.cs │ ├── PageListBlock.cs │ ├── SiteBlockData.cs │ ├── SiteLogotypeBlock.cs │ ├── TeaserBlock.cs │ └── _ReadMe.txt ├── HeadlessContent │ ├── IngredientBlock.cs │ └── RecipeBlock.cs ├── LoginViewModel.cs ├── Media │ ├── GenericMedia.cs │ ├── ImageFile.cs │ ├── VectorImageFile.cs │ └── VideoFile.cs ├── Pages │ ├── AllPropertiesTestPage.cs │ ├── ArticlePage.cs │ ├── ContactPage.cs │ ├── ContainerPage.cs │ ├── IHasRelatedContent.cs │ ├── ISearchPage.cs │ ├── LandingPage.cs │ ├── NewsPage.cs │ ├── ProductPage.cs │ ├── SearchPage.cs │ ├── SitePageData.cs │ ├── StandardPage.cs │ ├── StartPage.cs │ └── _ReadMe.txt ├── Register │ └── RegisterViewModel.cs ├── SiteContentType.cs ├── SiteImageUrl.cs └── ViewModels │ ├── ContactBlockModel.cs │ ├── ContentRenderingErrorModel.cs │ ├── IPageViewModel.cs │ ├── ImageViewModel.cs │ ├── LayoutModel.cs │ ├── PageListModel.cs │ ├── PageViewModel.cs │ ├── PreviewModel.cs │ ├── SearchContentModel.cs │ └── VideoViewModel.cs ├── NuGet.config ├── Program.cs ├── Properties ├── AssemblyInfo.cs └── launchSettings.json ├── Resources └── LanguageFiles │ ├── ContentTypeNames.xml │ ├── Display.xml │ ├── EditorHints.xml │ ├── GroupNames.xml │ ├── PropertyNames.xml │ ├── Views.xml │ └── _ReadMe.txt ├── Startup.cs ├── Views ├── ArticlePage │ └── Index.cshtml ├── LandingPage │ └── Index.cshtml ├── NewsGeneratorPlugin │ └── Index.cshtml ├── NewsPage │ └── Index.cshtml ├── Preview │ └── Index.cshtml ├── ProductPage │ └── Index.cshtml ├── Register │ └── Index.cshtml ├── SearchPage │ └── Index.cshtml ├── Shared │ ├── Blocks │ │ ├── ButtonBlock.cshtml │ │ ├── EditorialBlock.cshtml │ │ ├── JumbotronBlockWide.cshtml │ │ ├── NoRenderer.cshtml │ │ ├── SiteLogotypeBlock.cshtml │ │ ├── TeaserBlock.cshtml │ │ └── TeaserBlockWide.cshtml │ ├── Breadcrumbs.cshtml │ ├── Components │ │ ├── ContactBlock │ │ │ └── Default.cshtml │ │ ├── ImageFile │ │ │ └── Default.cshtml │ │ ├── PageListBlock │ │ │ └── Default.cshtml │ │ └── VideoFile │ │ │ └── Default.cshtml │ ├── DisplayTemplates │ │ ├── ContactPage.cshtml │ │ ├── DateTime.cshtml │ │ ├── Image.cshtml │ │ ├── StringsCollection.cshtml │ │ └── _ReadMe.txt │ ├── Footer.cshtml │ ├── Header.cshtml │ ├── Layouts │ │ ├── _LeftNavigation.cshtml │ │ ├── _Root.cshtml │ │ └── _TwoPlusOne.cshtml │ ├── PagePartials │ │ ├── ContactPage.cshtml │ │ ├── ContactPageWide.cshtml │ │ ├── Page.cshtml │ │ └── PageWide.cshtml │ ├── Readonly.cshtml │ ├── SubNavigation.cshtml │ ├── TemplateError.cshtml │ └── TemplateHint.cshtml ├── StandardPage │ └── Index.cshtml ├── StartPage │ └── Index.cshtml ├── Web.config ├── _ReadMe.txt ├── _ViewImports.cshtml └── _viewstart.cshtml ├── appsettings.Development.json ├── appsettings.json ├── bundleconfig.json ├── docker-compose.yml ├── docker ├── Sql.Dockerfile ├── Web.Dockerfile ├── build-script │ ├── attach_db.sh │ └── wait_sqlserver_start_and_attachdb.sh ├── build.ps1 └── run-script │ ├── build.sh │ ├── build_web_only.sh │ ├── run.sh │ ├── stop.sh │ └── stop_web_only.sh ├── favicon.ico ├── module.config ├── modulesbin └── .gitkeep └── wwwroot ├── ClientResources ├── Images │ └── icons │ │ └── layoutIcons24x24.png ├── Scripts │ └── Editors │ │ └── StringList.js └── Styles │ ├── LayoutIcons.css │ └── Styles.css ├── css ├── bootstrap-collapse.js ├── bootstrap-responsive.css ├── bootstrap.css ├── editmode.css ├── editor.css ├── media.css └── style.css ├── gfx ├── New_FDT_Press_Contact_.JPG ├── carouselbackground.png ├── contact.jpg ├── exampelspan4.png ├── experts.png ├── fallows-media-wide.jpg ├── leader.png ├── leader2.png ├── logotype.png ├── meet.jpg ├── page-type-thumbnail-article.png ├── page-type-thumbnail-contact.png ├── page-type-thumbnail-product.png ├── page-type-thumbnail-standard.png ├── page-type-thumbnail.png ├── person.png ├── plan.jpg ├── play.png ├── playInactive.png ├── productLandingv2.png ├── searchbutton.png ├── searchbuttonsmall.png └── track.jpg ├── img ├── favicon.ico ├── glyphicons-halflings-white.png └── glyphicons-halflings.png ├── js ├── bootstrap.js └── jquery.js └── jwplayer ├── jwplayer.js ├── player.swf ├── preview.jpg └── video.mp4 /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Nuget client Continuous integration 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | - 'develop' 8 | - 'netcore' 9 | - 'release/*' 10 | pull_request: 11 | branches: 12 | - '*' 13 | - '!master' 14 | jobs: 15 | build_test_pack: 16 | name: Build, test & pack 17 | runs-on: windows-latest 18 | env: 19 | buildConfiguration: release 20 | versionSuffix: ${{ github.ref == 'refs/heads/develop' && '-inte-' || contains(github.ref,'release/') && '-pre-' || '-ci-' }}${{github.RUN_NUMBER }} 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v1 24 | - name: Set up Node.js ⚙️ 25 | uses: actions/setup-node@v2 26 | with: 27 | node-version: '16' 28 | - name: Setup .NET Core @ Latest 29 | uses: actions/setup-dotnet@v1 30 | with: 31 | source-url: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json 32 | env: 33 | NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} 34 | - name: Restore 35 | run: dotnet restore PowerSlice.sln --configfile Nuget.config 36 | - name: Build (Release version) 37 | if: ${{ github.ref == 'refs/heads/master' }} 38 | run: dotnet build --no-restore --configuration $env:buildConfiguration 39 | - name: Build (Pre-Release version) 40 | if: ${{ github.ref != 'refs/heads/master' }} 41 | run: dotnet build --no-restore --configuration $env:buildConfiguration --version-suffix $env:versionSuffix 42 | - name: Test 43 | run: dotnet test --no-build --configuration $env:buildConfiguration 44 | - name: Pack (Release version) 45 | if: ${{ github.ref == 'refs/heads/master' }} 46 | run: | 47 | ./build/pack.ps1 48 | - name: Pack (Pre-Release version) 49 | if: ${{ github.ref != 'refs/heads/master' }} 50 | run: | 51 | ./build/pack.ps1 -versionSuffix $env:versionSuffix 52 | - name: Publish packages 53 | run: dotnet nuget push artifacts/**/*.nupkg --skip-duplicate -k ${{ secrets.GITHUB_TOKEN }} 54 | 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib/EPiServer.Cms.Shell.UI.dll 2 | packages/ 3 | 4 | ################# 5 | ## Eclipse 6 | ################# 7 | 8 | *.pydevproject 9 | .project 10 | .metadata 11 | bin/ 12 | tmp/ 13 | *.tmp 14 | *.bak 15 | *.swp 16 | *~.nib 17 | local.properties 18 | .classpath 19 | .settings/ 20 | .loadpath 21 | 22 | # External tool builders 23 | .externalToolBuilders/ 24 | 25 | # Locally stored "Eclipse launch configurations" 26 | *.launch 27 | 28 | # CDT-specific 29 | .cproject 30 | 31 | # PDT-specific 32 | .buildpath 33 | 34 | 35 | ################# 36 | ## Visual Studio 37 | ################# 38 | 39 | ## Ignore Visual Studio temporary files, build results, and 40 | ## files generated by popular Visual Studio add-ons. 41 | 42 | # User-specific files 43 | *.suo 44 | *.user 45 | *.sln.docstates 46 | 47 | # Build results 48 | [Dd]ebug/ 49 | [Rr]elease/ 50 | *_i.c 51 | *_p.c 52 | *.ilk 53 | *.meta 54 | *.obj 55 | *.pch 56 | *.pdb 57 | *.pgc 58 | *.pgd 59 | *.rsp 60 | *.sbr 61 | *.tlb 62 | *.tli 63 | *.tlh 64 | *.tmp 65 | *.vspscc 66 | .builds 67 | *.dotCover 68 | 69 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 70 | #packages/ 71 | 72 | # Visual C++ cache files 73 | ipch/ 74 | *.aps 75 | *.ncb 76 | *.opensdf 77 | *.sdf 78 | 79 | # Visual Studio profiler 80 | *.psess 81 | *.vsp 82 | 83 | # ReSharper is a .NET coding add-in 84 | _ReSharper* 85 | 86 | # Installshield output folder 87 | [Ee]xpress 88 | 89 | # DocProject is a documentation generator add-in 90 | DocProject/buildhelp/ 91 | DocProject/Help/*.HxT 92 | DocProject/Help/*.HxC 93 | DocProject/Help/*.hhc 94 | DocProject/Help/*.hhk 95 | DocProject/Help/*.hhp 96 | DocProject/Help/Html2 97 | DocProject/Help/html 98 | 99 | # Click-Once directory 100 | publish 101 | 102 | # Others 103 | [Bb]in 104 | [Oo]bj 105 | sql 106 | TestResults 107 | *.Cache 108 | ClientBin 109 | stylecop.* 110 | ~$* 111 | *.dbmdl 112 | /.vs/**/* 113 | 114 | #Generated_Code #added for RIA/Silverlight projects 115 | 116 | # Backup & report files from converting an old project file to a newer 117 | # Visual Studio version. Backup files are not needed, because we have git ;-) 118 | _UpgradeReport_Files/ 119 | Backup*/ 120 | UpgradeLog*.XML 121 | 122 | 123 | 124 | ############ 125 | ## Windows 126 | ############ 127 | 128 | # Windows image file caches 129 | Thumbs.db 130 | 131 | # Folder config file 132 | Desktop.ini 133 | 134 | 135 | ############# 136 | ## Python 137 | ############# 138 | 139 | *.py[co] 140 | 141 | # Packages 142 | *.egg 143 | *.egg-info 144 | dist 145 | eggs 146 | parts 147 | bin 148 | var 149 | sdist 150 | develop-eggs 151 | .installed.cfg 152 | 153 | # Installer logs 154 | pip-log.txt 155 | 156 | # Unit test / coverage reports 157 | .coverage 158 | .tox 159 | 160 | #Translations 161 | *.mo 162 | 163 | #Mr Developer 164 | .mr.developer.cfg 165 | 166 | # Mac crap 167 | .DS_Store 168 | 169 | ## Ignore files generated or required by Episerver sample site 170 | sample/AlloyMvcTemplates/App_Data/** 171 | sample/AlloyMvcTemplates/App_Code/** 172 | /nupkgs 173 | /modules 174 | /zipoutput 175 | -------------------------------------------------------------------------------- /.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/.nuget/NuGet.exe -------------------------------------------------------------------------------- /NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /PowerSlice.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31702.278 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerSlice", "PowerSlice\PowerSlice.csproj", "{5F76D9CF-1487-465F-B092-B3E4F44EF0FF}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{3A99A9FC-C2FC-4774-8827-6E340B6990E9}" 9 | ProjectSection(SolutionItems) = preProject 10 | .nuget\NuGet.Config = .nuget\NuGet.Config 11 | .nuget\NuGet.exe = .nuget\NuGet.exe 12 | .nuget\NuGet.targets = .nuget\NuGet.targets 13 | EndProjectSection 14 | EndProject 15 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C981ACCA-4C09-4B23-A702-B05AC309746B}" 16 | EndProject 17 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AlloyMvcTemplates", "sample\AlloyMvcTemplates\AlloyMvcTemplates.csproj", "{03260AE9-96B1-44A0-A297-14F457B652EE}" 18 | EndProject 19 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample", "sample", "{F1D681DC-ADBB-4E05-957F-2C825B4E3FAB}" 20 | EndProject 21 | Global 22 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 23 | Debug|Any CPU = Debug|Any CPU 24 | Release|Any CPU = Release|Any CPU 25 | EndGlobalSection 26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 27 | {5F76D9CF-1487-465F-B092-B3E4F44EF0FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {5F76D9CF-1487-465F-B092-B3E4F44EF0FF}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {5F76D9CF-1487-465F-B092-B3E4F44EF0FF}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {5F76D9CF-1487-465F-B092-B3E4F44EF0FF}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {03260AE9-96B1-44A0-A297-14F457B652EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {03260AE9-96B1-44A0-A297-14F457B652EE}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {03260AE9-96B1-44A0-A297-14F457B652EE}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {03260AE9-96B1-44A0-A297-14F457B652EE}.Release|Any CPU.Build.0 = Release|Any CPU 35 | EndGlobalSection 36 | GlobalSection(SolutionProperties) = preSolution 37 | HideSolutionNode = FALSE 38 | EndGlobalSection 39 | GlobalSection(NestedProjects) = preSolution 40 | {03260AE9-96B1-44A0-A297-14F457B652EE} = {F1D681DC-ADBB-4E05-957F-2C825B4E3FAB} 41 | EndGlobalSection 42 | GlobalSection(ExtensibilityGlobals) = postSolution 43 | SolutionGuid = {A863676A-FDA2-4CE4-A877-55EC559C6B54} 44 | EndGlobalSection 45 | EndGlobal 46 | -------------------------------------------------------------------------------- /PowerSlice/ContentSliceComponent.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Shell.ViewComposition; 2 | 3 | namespace PowerSlice 4 | { 5 | public class ContentSliceComponent : ComponentBase 6 | { 7 | public ContentSliceComponent() 8 | : base("powerslice/components/ContentSlice") 9 | { 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /PowerSlice/CreateOption.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Core; 2 | 3 | namespace PowerSlice 4 | { 5 | public class CreateOption 6 | { 7 | public CreateOption(string label, ContentReference parent, int contentTypeId) 8 | { 9 | Label = label; 10 | Parent = parent; 11 | ContentTypeId = contentTypeId; 12 | } 13 | 14 | public string Label { get; private set; } 15 | public ContentReference Parent { get; private set; } 16 | public int ContentTypeId { get; private set; } 17 | } 18 | } -------------------------------------------------------------------------------- /PowerSlice/IContentSlice.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EPiServer.Shell.ContentQuery; 3 | 4 | namespace PowerSlice 5 | { 6 | public interface IContentSlice : IContentQuery, ISortableContentSlice 7 | { 8 | int Order { get; } 9 | IEnumerable CreateOptions { get; } 10 | } 11 | } -------------------------------------------------------------------------------- /PowerSlice/ISortableContentSlice.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace PowerSlice 4 | { 5 | public interface ISortableContentSlice 6 | { 7 | IEnumerable SortOptions { get; } 8 | SortOption DefaultSortOption { get; } 9 | bool HideSortOptions { get; } 10 | } 11 | 12 | public interface ISortableContentSlice : ISortableContentSlice 13 | { 14 | IEnumerable> SortActions { get; } 15 | } 16 | } -------------------------------------------------------------------------------- /PowerSlice/InitializationModule.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Framework; 2 | using EPiServer.Framework.Initialization; 3 | using EPiServer.ServiceLocation; 4 | using EPiServer.Shell.Modules; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace PowerSlice 13 | { 14 | [InitializableModule] 15 | [ModuleDependency(typeof(EPiServer.Web.InitializationModule), typeof(EPiServer.Shell.ShellInitialization))] 16 | public class InitializationModule : IConfigurableModule 17 | { 18 | /// 19 | /// Configure the container for this module 20 | /// 21 | /// The EPiServer context 22 | public void ConfigureContainer(ServiceConfigurationContext context) 23 | { 24 | context.Services.Configure(o => 25 | { 26 | if (!o.Items.Any(x => x.Name.Equals("PowerSlice"))) 27 | { 28 | o.Items.Add(new ModuleDetails() { Name = "PowerSlice" }); 29 | } 30 | }); 31 | } 32 | 33 | /// 34 | /// Initialize this module 35 | /// 36 | /// The EPiServer initialization context 37 | public void Initialize(InitializationEngine context) 38 | { 39 | } 40 | 41 | /// 42 | /// Un-initialize this module 43 | /// 44 | /// The EPiServer initialization context 45 | public void Uninitialize(InitializationEngine context) 46 | { 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /PowerSlice/PowerSlice.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | PowerSlice 7 | net6.0 8 | Library 9 | PowerSlice.nuspec 10 | true 11 | $(SolutionDir)artifacts\packages\ 12 | Configuration=$(Configuration);version=$(PackageVersion);coreVersion=$(coreVersion);coreNextMajorVersion=$(coreNextMajorVersion);findVersion=$(findVersion);findNextMajorVersion=$(findNextMajorVersion);fwVersion=$(fwVersion);fwNextMajorVersion=$(fwNextMajorVersion) 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /PowerSlice/PowerSlice.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PowerSlice 5 | $version$ 6 | $title$ 7 | EPiServer AB and Abrahamsson Software AB 8 | EPiServer AB 9 | false 10 | Easily list EPiServer CMS content for editors 11 | Copyright 2022 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /PowerSlice/SlicesComponent.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using EPiServer.ServiceLocation; 4 | using EPiServer.Shell.ViewComposition; 5 | 6 | namespace PowerSlice 7 | { 8 | [Component] 9 | public class SlicesComponent : ComponentDefinitionBase 10 | { 11 | private IEnumerable _slices; 12 | 13 | public SlicesComponent() 14 | : this(ServiceLocator.Current.GetAllInstances()) {} 15 | 16 | public SlicesComponent(IEnumerable slices) : base("powerslice/components/ContentSlice") 17 | { 18 | _slices = slices.OrderBy(x => x.SortOrder); 19 | Categories = new [] { "cms" }; 20 | 21 | PlugInAreas = new [] { "/episerver/cms/assets" }; 22 | base.Title = "Powerslice"; 23 | } 24 | 25 | /// 26 | /// Creates the component. 27 | /// 28 | /// The component 29 | public override IComponent CreateComponent() 30 | { 31 | var component = base.CreateComponent(); 32 | component.Settings.Add(new Setting("queries", _slices.Select(s => new 33 | { 34 | Name = s.Name, 35 | DisplayName = s.DisplayName, 36 | CreateOptions = s.CreateOptions, 37 | Order = s.Order, 38 | PlugInAreas = s.PlugInAreas, 39 | Rank = s.Rank, 40 | SortOrder = s.SortOrder, 41 | VersionSpecific = s.VersionSpecific, 42 | DefaultSortOption = s.DefaultSortOption, 43 | HideSortOptions = s.HideSortOptions, 44 | SortOptions = s.SortOptions, 45 | }).ToList(), false)); 46 | return component; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /PowerSlice/SortAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EPiServer.Find; 3 | using EPiServer.Find.Api; 4 | 5 | namespace PowerSlice 6 | { 7 | public class SortAction : SortOption 8 | { 9 | public Func, SortOrder, ITypeSearch> SortFunction { get; private set; } 10 | 11 | public SortAction(string label, string key, Func, SortOrder, ITypeSearch> sortFunction) 12 | : base(label, key) 13 | { 14 | SortFunction = sortFunction; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /PowerSlice/SortOption.cs: -------------------------------------------------------------------------------- 1 | namespace PowerSlice 2 | { 3 | public class SortOption 4 | { 5 | public string Label { get; private set; } 6 | public string Key { get; private set; } 7 | public bool OrderDescending { get; set; } 8 | 9 | public SortOption(string label, string key) 10 | { 11 | Label = label; 12 | Key = key; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /PowerSlice/clientResources/PowerSlice/Components/ContentSliceGrid.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "dojo/_base/declare", 3 | "dojo/_base/lang", 4 | "epi-cms/component/ContentQueryGrid" 5 | ], function (declare, lang, ContentQueryGrid) { 6 | 7 | return declare([ContentQueryGrid], { 8 | sortKey: null, 9 | descending: false, 10 | 11 | _onContextChangedReloadTimeout: null, 12 | _refreshInterval: 5000, 13 | 14 | fetchData: function () { 15 | var queryOptions = { ignore: ["query"] }; 16 | if (this.sortKey) { 17 | queryOptions.sort = [{ attribute: this.sortKey, descending: this.descending }]; 18 | } 19 | this.grid.set("queryOptions", queryOptions); 20 | 21 | var queryParameters = this.queryParameters || {}; 22 | queryParameters.query = this.queryName; 23 | this.grid.set("query", queryParameters); 24 | }, 25 | 26 | onContextChanged: function (context) { 27 | // Using a timeout on context change events to avoid reloading before newly indexed content is searchable 28 | clearTimeout(this._onContextChangedReloadTimeout); 29 | this._onContextChangedReloadTimeout = setTimeout(lang.hitch(this, function() { 30 | this.fetchData(); 31 | }), this._refreshInterval); 32 | }, 33 | }); 34 | }); -------------------------------------------------------------------------------- /PowerSlice/clientResources/PowerSlice/Components/CreateSpecificContent.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "dojo/_base/declare", 3 | "dojo/_base/lang", 4 | "dojo/dom-attr", 5 | "dojo/promise/all", 6 | "epi/dependency", 7 | "epi-cms/contentediting/CreateContent", 8 | "epi/i18n!epi/cms/nls/episerver.cms.components.createpage" 9 | ], function (declare, lang, domAttr, all, dependency, CreateContent, res) { 10 | // summary: 11 | // Widget for language branch creation. 12 | 13 | return declare([CreateContent], { 14 | 15 | contentTypeStore: null, 16 | 17 | postMixInProperties: function () { 18 | this.inherited(arguments); 19 | 20 | if (!this.contentTypeStore) { 21 | var registry = dependency.resolve("epi.storeregistry"); 22 | this.contentTypeStore = registry.get("epi.cms.contenttype"); 23 | } 24 | }, 25 | 26 | postCreate: function () { 27 | this.inherited(arguments); 28 | this.skipContentTypeSelection = true; 29 | }, 30 | 31 | updateView: function (data) { 32 | this.set("res", res); 33 | 34 | var inherited = this.getInherited(arguments), 35 | self = this; 36 | 37 | all({ 38 | parent: this.model.contentDataStore.get(data.predefinedParentId), 39 | contentType: this.contentTypeStore.get(data.predefinedContentTypeId) 40 | }).then(function(results) { 41 | inherited.call(self, { 42 | requestedType: results.contentType.typeIdentifier, 43 | parent: results.parent 44 | }); 45 | self.model.set("contentName", data.predefinedContentName); 46 | } 47 | ); 48 | } 49 | }); 50 | }); -------------------------------------------------------------------------------- /PowerSlice/clientResources/PowerSlice/Components/templates/CreateContentInSliceDialog.html: -------------------------------------------------------------------------------- 1 | 
2 |
3 |
4 |
5 | 6 | 10 |
11 |
-------------------------------------------------------------------------------- /PowerSlice/clientResources/PowerSlice/Components/templates/Tasks.html: -------------------------------------------------------------------------------- 1 |
2 |
4 | 5 |
-------------------------------------------------------------------------------- /PowerSlice/clientResources/images/commonFormArrows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/PowerSlice/clientResources/images/commonFormArrows.png -------------------------------------------------------------------------------- /PowerSlice/clientResources/images/sortAscending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/PowerSlice/clientResources/images/sortAscending.png -------------------------------------------------------------------------------- /PowerSlice/clientResources/images/sortDescending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/PowerSlice/clientResources/images/sortDescending.png -------------------------------------------------------------------------------- /PowerSlice/clientResources/images/sorticon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/PowerSlice/clientResources/images/sorticon.png -------------------------------------------------------------------------------- /PowerSlice/lang/PowerSlice.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Reload 7 | 8 | Create content 9 | New 10 | 11 | Sort 12 | 13 | Name 14 | 15 | 16 | Publish date 17 | 18 | New {contentType} 19 | Filter 20 | 21 | 22 | 23 | Content name is required. 24 | 25 | Give your new content a name. 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /PowerSlice/module.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /PowerSlice/modules/_protected/Find/Find.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/PowerSlice/modules/_protected/Find/Find.zip -------------------------------------------------------------------------------- /PowerSlice/version.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5.2.0 5 | 6 | 7 | -------------------------------------------------------------------------------- /PowerSlice/web.config.transform: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PowerSlice 2 | 3 | ## How to build 4 | 5 | Build solution 6 | 7 | Run `pack.bat` 8 | 9 | 10 | ## Changelog 11 | 12 | 2017-12-21 build compatible with Episerver CMS 11 13 | 14 | Install prebuilt package and view *Version History* here: 15 | https://nuget.episerver.com/package/?id=PowerSlice 16 | -------------------------------------------------------------------------------- /assets/readme.txt: -------------------------------------------------------------------------------- 1 | Hi there PowerSlicer! 2 | 3 | === Get started === 4 | 1. Add a reference to EPiServer.Cms.Shell.UI.dll. 5 | 2. Create a slice by: 6 | 2.1 Creating a class inheriting ContentSliceBase 7 | 2.2 Annotating it with [ServiceConfiguration(typeof(IContentQuery)), ServiceConfiguration(typeof(IContentSlice))] 8 | 9 | === Simple example slice === 10 | [ServiceConfiguration(typeof(IContentQuery)), ServiceConfiguration(typeof(IContentSlice))] 11 | public class EverythingSlice : ContentSliceBase 12 | { 13 | public override string Name 14 | { 15 | get { return "Everything"; } 16 | } 17 | } 18 | 19 | Happy slicing! -------------------------------------------------------------------------------- /build/CopyZipFiles.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /build/DependencyVersions.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12.4.0 4 | 14.1.0 5 | 12.4.0 6 | 7 | -------------------------------------------------------------------------------- /build/get-version.ps1: -------------------------------------------------------------------------------- 1 | Param([string]$branchName, [Int]$buildCounter, [String]$publishPackagesParam) 2 | 3 | if (!$branchName -or !$buildCounter) { 4 | Write-Error "`$branchName and `$buildCounter parameters must be supplied" 5 | exit 1 6 | } 7 | 8 | Function GetVersion($path) { 9 | [xml] $versionFile = Get-Content $path 10 | return $versionFile.SelectSingleNode("Project/PropertyGroup/VersionPrefix").InnerText 11 | } 12 | 13 | $publishPackages = "False" 14 | if ($publishPackagesParam) { 15 | $publishPackages = $publishPackagesParam 16 | } 17 | 18 | $assemblyVersion = GetVersion "PowerSlice/version.props" 19 | 20 | if (!$assemblyVersion) { 21 | $assemblyVersion = "2.0.0" 22 | } 23 | 24 | if ("%publishPackages%" -eq "True") 25 | { 26 | $publishPackages = "True" 27 | } 28 | $informationalVersion = "$assemblyVersion" -f $buildCounter 29 | 30 | "AssemblyVersion: $assemblyVersion" 31 | "AssemblyInformationalVersion: $informationalVersion" 32 | 33 | "##teamcity[setParameter name='packageVersion' value='$informationalVersion']" 34 | "##teamcity[setParameter name='publishPackages' value='$publishPackages']" -------------------------------------------------------------------------------- /build/license.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(TargetsForTfmSpecificContentInPackage);IncludeLicenseFile 5 | $(BaseIntermediateOutputPath)$(PackageLicenseFile) 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /build/licenses/NO-THIRD-PARTY-LICENSES.txt: -------------------------------------------------------------------------------- 1 | No additional Implemented Software is included in this package. -------------------------------------------------------------------------------- /build/licenses/default-license-texts/ISC.txt: -------------------------------------------------------------------------------- 1 | ISC License: 2 | 3 | Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC") 4 | Copyright (c) 1995-2003 by Internet Software Consortium 5 | 6 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -------------------------------------------------------------------------------- /build/licenses/default-license-texts/MIT.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /build/licenses/default-license-texts/Ms-PL.txt: -------------------------------------------------------------------------------- 1 | Ms-PL Microsoft Public License (Ms-PL) 2 | 3 | This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. 4 | 5 | Definitions 6 | The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. 7 | 8 | A "contribution" is the original software, or any additions or changes to the software. 9 | 10 | A "contributor" is any person that distributes its contribution under this license. 11 | 12 | "Licensed patents" are a contributor's patent claims that read directly on its contribution. 13 | 14 | Grant of Rights 15 | (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. 16 | 17 | (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. 18 | 19 | Conditions and Limitations 20 | (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. 21 | 22 | (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. 23 | 24 | (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. 25 | 26 | (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. 27 | 28 | (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. -------------------------------------------------------------------------------- /build/licenses/default-license-texts/README: -------------------------------------------------------------------------------- 1 | Files taken from https://github.com/spdx/license-list -------------------------------------------------------------------------------- /build/nuspec.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | $(ProjectDir)..\..\ 5 | $(VersionPrefix)$(VersionSuffix) 6 | Configuration=$(Configuration);Version=$(PackageVersion) 7 | $(SolutionDir)artifacts\packages\ 8 | $(TargetsForTfmSpecificContentInPackage);GenerateLicenseFiles 9 | $(SolutionDir)build\licenses\NO-THIRD-PARTY-LICENSES.txt 10 | $(SolutionDir)build\licenses\LICENSE.txt.template 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /build/pack.ps1: -------------------------------------------------------------------------------- 1 | param ([string]$versionSuffix = "", 2 | [string]$configuration = "Release") 3 | $ErrorActionPreference = "Stop" 4 | 5 | # Set location to the Solution directory 6 | (Get-Item $PSScriptRoot).Parent.FullName | Push-Location 7 | 8 | [xml] $versionFile = Get-Content "./build/DependencyVersions.props" 9 | $node = $versionFile.SelectSingleNode("Project/PropertyGroup/CmsCoreVersionCommon") 10 | $coreVersion = $node.InnerText 11 | $parts = $coreVersion.Split(".") 12 | $major = [int]::Parse($parts[0]) + 1 13 | $coreNextMajorVersion = ($major.ToString() + ".0.0") 14 | 15 | $findNode = $versionFile.SelectSingleNode("Project/PropertyGroup/FindVersionCommon") 16 | $findVersion = $findNode.InnerText 17 | $findParts = $findVersion.Split(".") 18 | $findMajor = [int]::Parse($findParts[0]) + 1 19 | $findNextMajorVersion = $findMajor.ToString() 20 | 21 | $fwNode = $versionFile.SelectSingleNode("Project/PropertyGroup/FrameworkVersionCommon") 22 | $fwVersion = $fwNode.InnerText 23 | $fwParts = $fwVersion.Split(".") 24 | $fwMajor = [int]::Parse($fwParts[0]) + 1 25 | $fwNextMajorVersion = ($fwMajor.ToString() + ".0.0") 26 | 27 | [xml] $versionFile = Get-Content "./PowerSlice/version.props" 28 | $pVersion = $versionFile.SelectSingleNode("Project/PropertyGroup/VersionPrefix").InnerText + $versionSuffix 29 | 30 | Remove-Item -Path ./zipoutput -Recurse -Force -Confirm:$false -ErrorAction Ignore 31 | Copy-Item "./PowerSlice/clientResources/PowerSlice" -Destination "./zipoutput/PowerSlice/clientResources/PowerSlice" -Recurse 32 | 33 | New-Item -Path "./zipoutput/PowerSlice" -Name "$pVersion" -ItemType "directory" 34 | [xml] $moduleFile = Get-Content "./PowerSlice/module.config" 35 | $module = $moduleFile.SelectSingleNode("module") 36 | $module.Attributes["clientResourceRelativePath"].Value = $pVersion 37 | $moduleFile.Save("./zipoutput/PowerSlice/module.config") 38 | Move-Item -Path "./zipoutput/PowerSlice/clientResources" -Destination "./zipoutput/PowerSlice/$pVersion/clientresources" 39 | 40 | Copy-Item "./PowerSlice/clientResources/css" -Destination "./zipoutput/PowerSlice/$pVersion/clientResources/css" -Recurse 41 | Copy-Item "./PowerSlice/clientResources/images" -Destination "./zipoutput/PowerSlice/$pVersion/clientResources/images" -Recurse 42 | 43 | $compress = @{ 44 | Path = "./zipoutput/PowerSlice/*" 45 | CompressionLevel = "Optimal" 46 | DestinationPath = "./zipoutput/PowerSlice.zip" 47 | } 48 | Compress-Archive @compress 49 | 50 | dotnet pack --no-restore --no-build -c $configuration /p:PackageVersion=$pVersion /p:CoreVersion=$coreVersion /p:CoreNextMajorVersion=$coreNextMajorVersion /p:FindVersion=$findVersion /p:FindindNextMajorVersion=$findNextMajorVersion /p:FwVersion=$fwVersion /p:FwNextMajorVersion=$fwNextMajorVersion PowerSlice.sln 51 | 52 | Pop-Location 53 | 54 | -------------------------------------------------------------------------------- /build/tasks/extract.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const decompress = require('gulp-decompress'), 4 | fs = require('fs'), 5 | gulp = require('gulp'), 6 | gutil = require('gulp-util'), 7 | path = require('path'); 8 | 9 | let tasks = () => { 10 | 11 | gulp.task('extract-js-sources', (done) => { 12 | const zipFile = path.resolve('build/resources/EPiServer.UI.Sources.zip'), 13 | destination = path.resolve('test/DtkBinaries/dojo-release-1.8.9-src'); 14 | 15 | fs.stat(destination, (err, stat) => { 16 | if (stat && stat.isDirectory()) { 17 | gutil.log(zipFile, 'has already been decompressed to:', destination); 18 | return done(); 19 | } 20 | 21 | gulp.src(zipFile) 22 | .pipe(decompress({})) 23 | .pipe(gulp.dest(destination)) 24 | .on('end', done); 25 | }); 26 | }); 27 | }; 28 | 29 | module.exports = tasks; 30 | -------------------------------------------------------------------------------- /build/tasks/unit-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const gulp = require('gulp'), 4 | path = require('path'), 5 | testRunner = require('test-runner'), 6 | url = require('url'); 7 | 8 | let tasks = (reporter, port)=> { 9 | 10 | // The code in mocha-phantomjs is not loading the 3rd-party reportes using require 11 | // so we need to specify the path to the reporter 12 | // see: https://github.com/nathanboktae/mocha-phantomjs/issues/135 13 | if (reporter === 'teamcity') { 14 | reporter = path.resolve(__dirname, '../../node_modules/mocha-teamcity-reporter/lib/teamcity.js'); 15 | } 16 | 17 | function start(sitePath, port, done) { 18 | port = 8080 + (port % 5000); 19 | const localUri = 'http://localhost:' + port; 20 | 21 | const dnx = new testRunner.dnx(sitePath, port); 22 | dnx.start().then(()=> { 23 | const configurations = [ 24 | { 25 | title: 'Mocha Unit Tests', 26 | enabled: true, 27 | runner: 'mocha-phantomjs', 28 | args: ['-R', reporter, '-t', 60000, localUri] 29 | }]; 30 | 31 | var tearDownTimeout = setTimeout(function () { 32 | testRunner.runner.kill(); 33 | }, 300000); 34 | 35 | testRunner.runner.run(configurations) 36 | .then((success) => { 37 | dnx.kill(); 38 | if (!success) { 39 | done('Unit Tests failed') 40 | } else { 41 | done(); 42 | } 43 | }) 44 | .catch(function (error) { 45 | console.error(error); 46 | dnx.kill(); 47 | done(error); 48 | }) 49 | .finally(function () { 50 | clearTimeout(tearDownTimeout); 51 | }); 52 | }); 53 | }; 54 | 55 | gulp.task('run-js-tests', ['extract-js-sources'], (done) => { 56 | start(path.join(__dirname, '../../test/EPiServer.Marketing.Testing.Web.ClientTest'), port, done); 57 | }); 58 | }; 59 | 60 | module.exports = tasks; 61 | -------------------------------------------------------------------------------- /build/test.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | true 5 | true 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /pack.bat: -------------------------------------------------------------------------------- 1 | .nuget\NuGet.exe pack PowerSlice\PowerSlice.csproj -Properties Configuration=Release -OutputDirectory .\build\output 2 | pause -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/.gitignore: -------------------------------------------------------------------------------- 1 | modules/** 2 | wwwroot/js/script.min.js 3 | wwwroot/css/css.min.css -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/AlloyMvcTemplates.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | NU5100 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | PreserveNewest 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/Channels/DisplayResolutionBase.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Framework.Localization; 2 | using EPiServer.ServiceLocation; 3 | using EPiServer.Web; 4 | 5 | namespace AlloyTemplates.Business.Channels 6 | { 7 | /// 8 | /// Base class for all resolution definitions 9 | /// 10 | public abstract class DisplayResolutionBase : IDisplayResolution 11 | { 12 | private readonly LocalizationService _localizationService; 13 | protected DisplayResolutionBase(LocalizationService localizationService, string name, int width, int height) 14 | { 15 | _localizationService = localizationService; 16 | Id = GetType().FullName; 17 | Name = Translate(name); 18 | Width = width; 19 | Height = height; 20 | } 21 | 22 | /// 23 | /// Gets the unique ID for this resolution 24 | /// 25 | public string Id { get; protected set; } 26 | 27 | /// 28 | /// Gets the name of resolution 29 | /// 30 | public string Name { get; protected set; } 31 | 32 | /// 33 | /// Gets the resolution width in pixels 34 | /// 35 | public int Width { get; protected set; } 36 | 37 | /// 38 | /// Gets the resolution height in pixels 39 | /// 40 | public int Height { get; protected set; } 41 | 42 | private string Translate(string resurceKey) 43 | { 44 | string value; 45 | 46 | if (!_localizationService.TryGetString(resurceKey, out value)) 47 | { 48 | value = resurceKey; 49 | } 50 | 51 | return value; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/Channels/DisplayResolutions.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Framework.Localization; 2 | 3 | namespace AlloyTemplates.Business.Channels 4 | { 5 | /// 6 | /// Defines resolution for desktop displays 7 | /// 8 | public class StandardResolution : DisplayResolutionBase 9 | { 10 | public StandardResolution(LocalizationService localizationService) : base(localizationService, "/resolutions/standard", 1366, 768) 11 | { 12 | } 13 | } 14 | 15 | /// 16 | /// Defines resolution for a horizontal iPad 17 | /// 18 | public class IpadHorizontalResolution : DisplayResolutionBase 19 | { 20 | public IpadHorizontalResolution(LocalizationService localizationService) : base(localizationService, "/resolutions/ipadhorizontal", 1024, 768) 21 | { 22 | } 23 | } 24 | 25 | /// 26 | /// Defines resolution for a vertical iPhone 5s 27 | /// 28 | public class IphoneVerticalResolution : DisplayResolutionBase 29 | { 30 | public IphoneVerticalResolution(LocalizationService localizationService) : base(localizationService, "/resolutions/iphonevertical", 320, 568) 31 | { 32 | } 33 | } 34 | 35 | /// 36 | /// Defines resolution for a vertical Android handheld device 37 | /// 38 | public class AndroidVerticalResolution : DisplayResolutionBase 39 | { 40 | public AndroidVerticalResolution(LocalizationService localizationService) : base(localizationService, "/resolutions/androidvertical", 480, 800) 41 | { 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/Channels/MobileChannel.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Web; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Wangkanai.Detection; 5 | 6 | namespace AlloyTemplates.Business.Channels 7 | { 8 | // 9 | //Defines the 'Mobile' content channel 10 | // 11 | public class MobileChannel : DisplayChannel 12 | { 13 | public const string Name = "mobile"; 14 | 15 | public override string ChannelName 16 | { 17 | get 18 | { 19 | return Name; 20 | } 21 | } 22 | 23 | public override string ResolutionId 24 | { 25 | get 26 | { 27 | return typeof(IphoneVerticalResolution).FullName; 28 | } 29 | } 30 | 31 | //CMS-16684: ASPNET Core doesn't natively support checking device, we need to reimplement this 32 | public override bool IsActive(HttpContext context) 33 | { 34 | var detection = context.RequestServices.GetRequiredService(); 35 | return detection.Device.Type == DeviceType.Mobile; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/Channels/WebChannel.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Web; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Wangkanai.Detection; 5 | 6 | namespace AlloyTemplates.Business.Channels 7 | { 8 | /// 9 | /// Defines the 'Web' content channel 10 | /// 11 | public class WebChannel : DisplayChannel 12 | { 13 | public override string ChannelName 14 | { 15 | get 16 | { 17 | return "web"; 18 | } 19 | } 20 | 21 | //CMS-16684: ASPNET Core doesn't natively support checking device, we need to reimplement this 22 | public override bool IsActive(HttpContext context) 23 | { 24 | var detection = context.RequestServices.GetRequiredService(); 25 | return detection.Device.Type == DeviceType.Desktop; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/ContentExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using EPiServer.Core; 4 | using EPiServer.Filters; 5 | using EPiServer.Framework.Web; 6 | using EPiServer.ServiceLocation; 7 | 8 | namespace AlloyTemplates.Business 9 | { 10 | /// 11 | /// Extension methods for content 12 | /// 13 | public static class ContentExtensions 14 | { 15 | /// 16 | /// Filters content which should not be visible to the user. 17 | /// 18 | public static IEnumerable FilterForDisplay(this IEnumerable contents, bool requirePageTemplate = false, bool requireVisibleInMenu = false) 19 | where T : IContent 20 | { 21 | var accessFilter = new FilterAccess(); 22 | var publishedFilter = new FilterPublished(); 23 | contents = contents.Where(x => !publishedFilter.ShouldFilter(x) && !accessFilter.ShouldFilter(x)); 24 | if (requirePageTemplate) 25 | { 26 | var templateFilter = ServiceLocator.Current.GetInstance(); 27 | templateFilter.TemplateTypeCategories = TemplateTypeCategories.Request; 28 | contents = contents.Where(x => !templateFilter.ShouldFilter(x)); 29 | } 30 | if (requireVisibleInMenu) 31 | { 32 | contents = contents.Where(x => VisibleInMenu(x)); 33 | } 34 | return contents; 35 | } 36 | 37 | private static bool VisibleInMenu(IContent content) 38 | { 39 | var page = content as PageData; 40 | if (page == null) 41 | { 42 | return true; 43 | } 44 | return page.VisibleInMenu; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/EditorDescriptors/ContactPageSelectionFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using EPiServer.ServiceLocation; 4 | using EPiServer.Shell.ObjectEditing; 5 | 6 | namespace AlloyTemplates.Business.EditorDescriptors 7 | { 8 | /// 9 | /// Provides a list of options corresponding to ContactPage pages on the site 10 | /// 11 | /// 12 | [ServiceConfiguration] 13 | public class ContactPageSelectionFactory : ISelectionFactory 14 | { 15 | private readonly ContentLocator _contentLocator; 16 | 17 | public ContactPageSelectionFactory(ContentLocator contentLocator) 18 | { 19 | _contentLocator = contentLocator; 20 | } 21 | 22 | public IEnumerable GetSelections(ExtendedMetadata metadata) 23 | { 24 | var contactPages = _contentLocator.GetContactPages(); 25 | 26 | return new List(contactPages.Select(c => new SelectItem { Value = c.PageLink, Text = c.Name })); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/EditorDescriptors/ContactPageSelector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using EPiServer.Core; 4 | using EPiServer.Shell.ObjectEditing; 5 | using EPiServer.Shell.ObjectEditing.EditorDescriptors; 6 | 7 | namespace AlloyTemplates.Business.EditorDescriptors 8 | { 9 | /// 10 | /// Registers an editor to select a ContactPage for a PageReference property using a dropdown 11 | /// 12 | [EditorDescriptorRegistration(TargetType = typeof(PageReference), UIHint = Global.SiteUIHints.Contact)] 13 | public class ContactPageSelector : EditorDescriptor 14 | { 15 | public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable attributes) 16 | { 17 | SelectionFactoryType = typeof(ContactPageSelectionFactory); 18 | 19 | ClientEditingClass = "epi-cms/contentediting/editors/SelectionEditor"; 20 | 21 | base.ModifyMetadata(metadata, attributes); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/IModifyLayout.cs: -------------------------------------------------------------------------------- 1 | using AlloyTemplates.Models.ViewModels; 2 | 3 | namespace AlloyTemplates.Business 4 | { 5 | /// 6 | /// Defines a method which may be invoked by PageContextActionFilter allowing controllers 7 | /// to modify common layout properties of the view model. 8 | /// 9 | interface IModifyLayout 10 | { 11 | void ModifyLayout(LayoutModel layoutModel); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/Initialization/CustomizedRenderingInitialization.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Framework; 2 | using EPiServer.Framework.Initialization; 3 | using EPiServer.ServiceLocation; 4 | using AlloyTemplates.Business.Rendering; 5 | using EPiServer.Web; 6 | using EPiServer.Web.Mvc; 7 | using Microsoft.Extensions.DependencyInjection; 8 | using EPiServer.Web.Mvc.Html; 9 | 10 | namespace AlloyTemplates.Business.Initialization 11 | { 12 | /// 13 | /// Module for customizing templates and rendering. 14 | /// 15 | [ModuleDependency(typeof(InitializationModule))] 16 | public class CustomizedRenderingInitialization : IConfigurableModule 17 | { 18 | public void ConfigureContainer(ServiceConfigurationContext context) 19 | { 20 | //Implementations for custom interfaces can be registered here. 21 | context.ConfigurationComplete += (o, e) => 22 | { 23 | //Register custom implementations that should be used in favour of the default implementations 24 | context.Services.AddTransient() 25 | .AddTransient(); 26 | }; 27 | } 28 | 29 | public void Initialize(InitializationEngine context) => context.Locate.Advanced.GetInstance().TemplateResolved += TemplateCoordinator.OnTemplateResolved; 30 | 31 | public void Uninitialize(InitializationEngine context) => context.Locate.Advanced.GetInstance().TemplateResolved -= TemplateCoordinator.OnTemplateResolved; 32 | 33 | public void Preload(string[] parameters){} 34 | } 35 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/PageContextActionFilter.cs: -------------------------------------------------------------------------------- 1 | using AlloyTemplates.Models.Pages; 2 | using AlloyTemplates.Models.ViewModels; 3 | using EPiServer.Web.Routing; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.AspNetCore.Mvc.Filters; 6 | 7 | namespace AlloyTemplates.Business 8 | { 9 | /// 10 | /// Intercepts actions with view models of type IPageViewModel and populates the view models 11 | /// Layout and Section properties. 12 | /// 13 | /// 14 | /// This filter frees controllers for pages from having to care about common context needed by layouts 15 | /// and other page framework components allowing the controllers to focus on the specifics for the page types 16 | /// and actions that they handle. 17 | /// 18 | public class PageContextActionFilter : IResultFilter 19 | { 20 | private readonly PageViewContextFactory _contextFactory; 21 | public PageContextActionFilter(PageViewContextFactory contextFactory) 22 | { 23 | _contextFactory = contextFactory; 24 | } 25 | 26 | public void OnResultExecuting(ResultExecutingContext filterContext) 27 | { 28 | var controller = filterContext.Controller as Controller; 29 | var viewModel = controller?.ViewData.Model; 30 | 31 | var model = viewModel as IPageViewModel; 32 | if (model != null) 33 | { 34 | var currentContentLink = filterContext.HttpContext.GetContentLink(); 35 | 36 | var layoutModel = model.Layout ?? _contextFactory.CreateLayoutModel(currentContentLink, filterContext.HttpContext); 37 | 38 | var layoutController = filterContext.Controller as IModifyLayout; 39 | if(layoutController != null) 40 | { 41 | layoutController.ModifyLayout(layoutModel); 42 | } 43 | 44 | model.Layout = layoutModel; 45 | 46 | if (model.Section == null) 47 | { 48 | model.Section = _contextFactory.GetSection(currentContentLink); 49 | } 50 | } 51 | } 52 | 53 | public void OnResultExecuted(ResultExecutedContext filterContext) 54 | { 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/PageTypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EPiServer.DataAbstraction; 3 | using EPiServer.ServiceLocation; 4 | 5 | namespace AlloyTemplates.Business 6 | { 7 | /// 8 | /// Provides extension methods for types intended to be used when working with page types 9 | /// 10 | public static class PageTypeExtensions 11 | { 12 | /// 13 | /// Returns the definition for a specific page type 14 | /// 15 | /// 16 | /// 17 | public static PageType GetPageType(this Type pageType) 18 | { 19 | var pageTypeRepository = ServiceLocator.Current.GetInstance>(); 20 | 21 | return pageTypeRepository.Load(pageType); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/Rendering/AlloyContentAreaRenderer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EPiServer.Core; 3 | using EPiServer.Core.Html.StringParsing; 4 | using EPiServer.Web.Mvc.Html; 5 | using EPiServer; 6 | using Microsoft.AspNetCore.Mvc.Rendering; 7 | 8 | namespace AlloyTemplates.Business.Rendering 9 | { 10 | /// 11 | /// Extends the default to apply custom CSS classes to each . 12 | /// 13 | public class AlloyContentAreaRenderer : ContentAreaRenderer 14 | { 15 | protected override string GetContentAreaItemCssClass(IHtmlHelper htmlHelper, ContentAreaItem contentAreaItem) 16 | { 17 | var baseItemClass = base.GetContentAreaItemCssClass(htmlHelper, contentAreaItem); 18 | 19 | var tag = GetContentAreaItemTemplateTag(htmlHelper, contentAreaItem); 20 | return $"block {baseItemClass} {GetTypeSpecificCssClasses(contentAreaItem, ContentRepository)} {GetCssClassForTag(tag)} {tag}"; 21 | } 22 | 23 | /// 24 | /// Gets a CSS class used for styling based on a tag name (ie a Bootstrap class name) 25 | /// 26 | /// Any tag name available, see 27 | private static string GetCssClassForTag(string tagName) 28 | { 29 | if (string.IsNullOrEmpty(tagName)) 30 | { 31 | return ""; 32 | } 33 | switch (tagName.ToLower()) 34 | { 35 | case "span12": 36 | return "full"; 37 | case "span8": 38 | return "wide"; 39 | case "span6": 40 | return "half"; 41 | default: 42 | return string.Empty; 43 | } 44 | } 45 | 46 | private static string GetTypeSpecificCssClasses(ContentAreaItem contentAreaItem, IContentRepository contentRepository) 47 | { 48 | var content = contentAreaItem.GetContent(); 49 | var cssClass = content == null ? String.Empty : content.GetOriginalType().Name.ToLowerInvariant(); 50 | 51 | var customClassContent = content as ICustomCssInContentArea; 52 | if (customClassContent != null && !string.IsNullOrWhiteSpace(customClassContent.ContentAreaCssClass)) 53 | { 54 | cssClass += string.Format(" {0}", customClassContent.ContentAreaCssClass); 55 | } 56 | 57 | return cssClass; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/Rendering/ErrorHandlingContentRenderer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using EPiServer.Core; 4 | using EPiServer.DataAbstraction; 5 | 6 | using AlloyTemplates.Models.ViewModels; 7 | using EPiServer.Web.Mvc; 8 | using System.Diagnostics; 9 | using Microsoft.AspNetCore.Mvc.Rendering; 10 | using System.Threading.Tasks; 11 | using AlloyTemplates.Helpers; 12 | 13 | namespace AlloyTemplates.Business.Rendering 14 | { 15 | /// 16 | /// Wraps an MvcContentRenderer and adds error handling to ensure that blocks and other content 17 | /// rendered as parts of pages won't crash the entire page if a non-critical exception occurs while rendering it. 18 | /// 19 | /// 20 | /// Prints an error message for editors so that they can easily report errors to developers. 21 | /// 22 | public class ErrorHandlingContentRenderer : IContentRenderer 23 | { 24 | private readonly MvcContentRenderer _mvcRenderer; 25 | 26 | public ErrorHandlingContentRenderer(MvcContentRenderer mvcRenderer) 27 | { 28 | _mvcRenderer = mvcRenderer; 29 | } 30 | 31 | /// 32 | /// Renders the contentData using the wrapped renderer and catches common, non-critical exceptions. 33 | /// 34 | public async Task RenderAsync(IHtmlHelper helper, IContentData contentData, TemplateModel templateModel) 35 | { 36 | try 37 | { 38 | await _mvcRenderer.RenderAsync(helper, contentData, templateModel); 39 | } 40 | catch (Exception ex) when (!Debugger.IsAttached) 41 | { 42 | switch (ex) 43 | { 44 | case NullReferenceException: 45 | case ArgumentException: 46 | case ApplicationException: 47 | case InvalidOperationException: 48 | case NotImplementedException: 49 | case IOException: 50 | case EPiServerException: 51 | HandlerError(helper, contentData, ex); 52 | break; 53 | default: 54 | throw; 55 | } 56 | } 57 | } 58 | 59 | private void HandlerError(IHtmlHelper helper, IContentData contentData, Exception renderingException) 60 | { 61 | if (helper.ViewContext.IsInEditMode()) 62 | { 63 | var errorModel = new ContentRenderingErrorModel(contentData, renderingException); 64 | helper.RenderPartialAsync("TemplateError", errorModel).GetAwaiter().GetResult(); 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/Rendering/IContainerPage.cs: -------------------------------------------------------------------------------- 1 | namespace AlloyTemplates.Business.Rendering 2 | { 3 | /// 4 | /// Marker interface for content types which should not be handled by DefaultPageController. 5 | /// 6 | interface IContainerPage 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/Rendering/ICustomCssInContentArea.cs: -------------------------------------------------------------------------------- 1 | namespace AlloyTemplates.Business.Rendering 2 | { 3 | /// 4 | /// Defines a property for CSS class(es) which will be added to the class 5 | /// attribute of containing elements when rendered in a content area with a size tag. 6 | /// 7 | interface ICustomCssInContentArea 8 | { 9 | string ContentAreaCssClass { get; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/Rendering/SiteViewEngineLocationExpander.cs: -------------------------------------------------------------------------------- 1 | using AlloyTemplates.Business.Rendering; 2 | using Microsoft.AspNetCore.Mvc.Razor; 3 | using System.Collections.Generic; 4 | 5 | namespace AlloyMvcTemplates.Business.Rendering 6 | { 7 | 8 | public class SiteViewEngineLocationExpander : IViewLocationExpander 9 | { 10 | private static readonly string[] AdditionalPartialViewFormats = new[] 11 | { 12 | TemplateCoordinator.BlockFolder + "{0}.cshtml", 13 | TemplateCoordinator.PagePartialsFolder + "{0}.cshtml" 14 | }; 15 | 16 | public IEnumerable ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable viewLocations) 17 | { 18 | foreach (var location in viewLocations) 19 | { 20 | yield return location; 21 | } 22 | 23 | for (int i = 0; i < AdditionalPartialViewFormats.Length; i++) 24 | { 25 | yield return AdditionalPartialViewFormats[i]; 26 | } 27 | } 28 | public void PopulateValues(ViewLocationExpanderContext context) { } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Business/UIDescriptors/ContainerPageUIDescriptor.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Shell; 2 | using AlloyTemplates.Models.Pages; 3 | 4 | namespace AlloyTemplates.Business.UIDescriptors 5 | { 6 | /// 7 | /// Describes how the UI should appear for content. 8 | /// 9 | [UIDescriptorRegistration] 10 | public class ContainerPageUIDescriptor : UIDescriptor 11 | { 12 | public ContainerPageUIDescriptor() 13 | : base(ContentTypeCssClassNames.Container) 14 | { 15 | DefaultView = CmsViewNames.AllPropertiesView; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/ClientResources/Images/icons/editing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/ClientResources/Images/icons/editing.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/ClientResources/Images/icons/layoutIcons24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/ClientResources/Images/icons/layoutIcons24x24.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/ClientResources/Styles/Styles.css: -------------------------------------------------------------------------------- 1 | .epiStringList .dijitTextArea { 2 | width: 250px; 3 | } 4 | 5 | .epiStringList .epiStringListError .dijitTextArea { 6 | border: solid 1px #d46464; 7 | } 8 | 9 | .editorial-block-icon:before { 10 | content: ""; 11 | background: url("../Images/icons/editing.png"); 12 | background-repeat: no-repeat; 13 | display: inline-block; 14 | width: 16px; 15 | text-align: center; 16 | height: 16px; 17 | padding-right: 4px; 18 | margin-left: 4px; 19 | } 20 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Components/ImageFileViewComponent.cs: -------------------------------------------------------------------------------- 1 | using AlloyTemplates.Models.Media; 2 | using AlloyTemplates.Models.ViewModels; 3 | using EPiServer.Web.Mvc; 4 | using EPiServer.Web.Routing; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace AlloyTemplates.Controllers 8 | { 9 | /// 10 | /// Controller for the image file. 11 | /// 12 | public class ImageFileViewComponent : PartialContentComponent 13 | { 14 | private readonly UrlResolver _urlResolver; 15 | 16 | public ImageFileViewComponent(UrlResolver urlResolver) 17 | { 18 | _urlResolver = urlResolver; 19 | } 20 | 21 | /// 22 | /// The index action for the image file. Creates the view model and renders the view. 23 | /// 24 | /// The current image file. 25 | protected override IViewComponentResult InvokeComponent(ImageFile currentContent) 26 | { 27 | var model = new ImageViewModel 28 | { 29 | Url = _urlResolver.GetUrl(currentContent.ContentLink), 30 | Name = currentContent.Name, 31 | Copyright = currentContent.Copyright 32 | }; 33 | 34 | return View(model); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Components/VideoFileViewComponent.cs: -------------------------------------------------------------------------------- 1 | using AlloyTemplates.Models.Media; 2 | using AlloyTemplates.Models.ViewModels; 3 | using EPiServer.Core; 4 | using EPiServer.Web.Mvc; 5 | using EPiServer.Web.Routing; 6 | using Microsoft.AspNetCore.Mvc; 7 | using System; 8 | 9 | namespace AlloyTemplates.Controllers 10 | { 11 | /// 12 | /// Controller for the video file. 13 | /// 14 | public class VideoFileViewComponent : PartialContentComponent 15 | { 16 | private readonly UrlResolver _urlResolver; 17 | 18 | public VideoFileViewComponent(UrlResolver urlResolver) 19 | { 20 | _urlResolver = urlResolver; 21 | } 22 | 23 | /// 24 | /// The index action for the video file. Creates the view model and renders the view. 25 | /// 26 | /// The current video file. 27 | protected override IViewComponentResult InvokeComponent(VideoFile currentContent) 28 | { 29 | var model = new VideoViewModel 30 | { 31 | Url = _urlResolver.GetUrl(currentContent.ContentLink), 32 | PreviewImageUrl = ContentReference.IsNullOrEmpty(currentContent.PreviewImage) ? String.Empty : _urlResolver.GetUrl(currentContent.PreviewImage), 33 | }; 34 | 35 | return View(model); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Controllers/DefaultPageController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EPiServer; 3 | using EPiServer.Framework.DataAnnotations; 4 | using AlloyTemplates.Models.Pages; 5 | using AlloyTemplates.Models.ViewModels; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace AlloyTemplates.Controllers 9 | { 10 | /// 11 | /// Concrete controller that handles all page types that don't have their own specific controllers. 12 | /// 13 | /// 14 | /// Note that as the view file name is hard coded it won't work with DisplayModes (ie Index.mobile.cshtml). 15 | /// For page types requiring such views add specific controllers for them. Alternatively the Index action 16 | /// could be modified to set ControllerContext.RouteData.Values["controller"] to type name of the currentPage 17 | /// argument. That may however have side effects. 18 | /// 19 | [TemplateDescriptor(Inherited = true)] 20 | public class DefaultPageController : PageControllerBase 21 | { 22 | public ViewResult Index(SitePageData currentPage) 23 | { 24 | var model = CreateModel(currentPage); 25 | return View(string.Format("~/Views/{0}/Index.cshtml", currentPage.GetOriginalType().Name), model); 26 | } 27 | 28 | /// 29 | /// Creates a PageViewModel where the type parameter is the type of the page. 30 | /// 31 | /// 32 | /// Used to create models of a specific type without the calling method having to know that type. 33 | /// 34 | private static IPageViewModel CreateModel(SitePageData page) 35 | { 36 | var type = typeof(PageViewModel<>).MakeGenericType(page.GetOriginalType()); 37 | return Activator.CreateInstance(type, page) as IPageViewModel; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Controllers/PageControllerBase.cs: -------------------------------------------------------------------------------- 1 | using AlloyTemplates.Business; 2 | using AlloyTemplates.Models.Pages; 3 | using AlloyTemplates.Models.ViewModels; 4 | using EPiServer.Web.Mvc; 5 | using EPiServer.Shell.Security; 6 | using Microsoft.AspNetCore.Mvc; 7 | using System.Threading.Tasks; 8 | using EPiServer.Web.Routing; 9 | using Microsoft.Extensions.DependencyInjection; 10 | using Microsoft.AspNetCore.Authentication; 11 | using Microsoft.AspNetCore.Http; 12 | using EPiServer.ServiceLocation; 13 | using Microsoft.Extensions.Options; 14 | using EPiServer.Shell.Security.Internal; 15 | 16 | namespace AlloyTemplates.Controllers 17 | { 18 | /// 19 | /// All controllers that renders pages should inherit from this class so that we can 20 | /// apply action filters, such as for output caching site wide, should we want to. 21 | /// 22 | public abstract class PageControllerBase : PageController, IModifyLayout 23 | where T : SitePageData 24 | { 25 | protected Injected securityConfiguration; 26 | protected Injected contextAccessor; 27 | protected Injected> authenticationOptions; 28 | 29 | /// 30 | /// Signs out the current user and redirects to the Index action of the same controller. 31 | /// 32 | /// 33 | /// There's a log out link in the footer which should redirect the user to the same page. 34 | /// As we don't have a specific user/account/login controller but rely on the login URL for 35 | /// forms authentication for login functionality we add an action for logging out to all 36 | /// controllers inheriting from this class. 37 | /// 38 | public async Task Logout() 39 | { 40 | await SignOutAsync(); 41 | return Redirect(HttpContext.RequestServices.GetService().GetUrl(PageContext.ContentLink, PageContext.LanguageID)); 42 | } 43 | 44 | public virtual void ModifyLayout(LayoutModel layoutModel) 45 | { 46 | var page = PageContext.Page as SitePageData; 47 | if (page != null) 48 | { 49 | layoutModel.HideHeader = page.HideSiteHeader; 50 | layoutModel.HideFooter = page.HideSiteFooter; 51 | } 52 | } 53 | 54 | private async Task SignOutAsync() 55 | { 56 | var uiSignInManager = securityConfiguration.Service?.UiSignInManager; 57 | if (uiSignInManager != null) 58 | { 59 | await uiSignInManager.SignOutAsync(); 60 | return; 61 | } 62 | 63 | if (authenticationOptions.Service != null && contextAccessor.Service?.HttpContext != null) 64 | { 65 | foreach (var scheme in authenticationOptions.Service.Value.Schemes) 66 | { 67 | await contextAccessor.Service.HttpContext.SignOutAsync(scheme.Name); 68 | } 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Controllers/RouteAttributeController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | 3 | namespace CmsCore.Specs.WebSite.Controllers 4 | { 5 | public class RouteAttributeController : ControllerBase 6 | { 7 | public const string AttributeRoute = "goto-foo"; 8 | 9 | [Route(AttributeRoute)] 10 | public IActionResult Index() => Content("bar"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Controllers/SearchPageController.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using AlloyTemplates.Controllers; 3 | using AlloyTemplates.Models.Pages; 4 | using AlloyTemplates.Models.ViewModels; 5 | using Microsoft.AspNetCore.Mvc; 6 | using EPiServer.Shell.Search; 7 | 8 | namespace AlloyMvcTemplates.Controllers 9 | { 10 | public class SearchPageController : PageControllerBase 11 | { 12 | private SearchProvidersManager _searchProvidersManager; 13 | 14 | public SearchPageController(SearchProvidersManager searchProvidersManager) 15 | { 16 | _searchProvidersManager = searchProvidersManager; 17 | } 18 | 19 | public ViewResult Index(SearchPage currentPage, string q) 20 | { 21 | var providers = _searchProvidersManager.GetEnabledProvidersByPriority("CMS/pages", true); 22 | 23 | var hits = providers.SelectMany(p => p.Search(new Query(q))).ToList(); 24 | 25 | var model = new SearchContentModel(currentPage) 26 | { 27 | Hits = hits.Select(x => new SearchContentModel.SearchHit 28 | { 29 | Url = x.Url, 30 | Excerpt = x.PreviewText, 31 | Title = x.Title 32 | }), 33 | NumberOfHits = hits.Count, 34 | SearchServiceDisabled = false, 35 | SearchedQuery = q 36 | }; 37 | 38 | return View(model); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Controllers/StartPageController.cs: -------------------------------------------------------------------------------- 1 | using AlloyTemplates.Models.Pages; 2 | using AlloyTemplates.Models.ViewModels; 3 | using EPiServer.Web; 4 | using EPiServer.Web.Mvc; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace AlloyTemplates.Controllers 8 | { 9 | public class StartPageController : PageControllerBase 10 | { 11 | public IActionResult Index(StartPage currentPage) 12 | { 13 | var model = PageViewModel.Create(currentPage); 14 | 15 | if (SiteDefinition.Current.StartPage.CompareToIgnoreWorkID(currentPage.ContentLink)) // Check if it is the StartPage or just a page of the StartPage type. 16 | { 17 | //Connect the view models logotype property to the start page's to make it editable 18 | var editHints = ViewData.GetEditHints, StartPage>(); 19 | editHints.AddConnection(m => m.Layout.Logotype, p => p.SiteLogotype); 20 | editHints.AddConnection(m => m.Layout.ProductPages, p => p.ProductPageLinks); 21 | editHints.AddConnection(m => m.Layout.CompanyInformationPages, p => p.CompanyInformationPageLinks); 22 | editHints.AddConnection(m => m.Layout.NewsPages, p => p.NewsPageLinks); 23 | editHints.AddConnection(m => m.Layout.CustomerZonePages, p => p.CustomerZonePageLinks); 24 | } 25 | 26 | return View(model); 27 | } 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/CustomPowerSlice/ArticleSlice.cs: -------------------------------------------------------------------------------- 1 | using AlloyTemplates.Models.Pages; 2 | using EPiServer.Core; 3 | using EPiServer.ServiceLocation; 4 | using EPiServer.Shell.ContentQuery; 5 | using PowerSlice; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Web; 10 | 11 | namespace AlloyTemplates.MySlice 12 | { 13 | [ServiceConfiguration(typeof(IContentQuery)), ServiceConfiguration(typeof(IContentSlice))] 14 | public class ArticleSlice : ContentSliceBase 15 | { 16 | public override string Name 17 | { 18 | get { return "Articles"; } 19 | } 20 | public override IEnumerable CreateOptions 21 | { 22 | get 23 | { 24 | var contentType = ContentTypeRepository.Load(typeof(ArticlePage)); 25 | yield return new CreateOption(contentType.LocalizedName, ContentReference.StartPage, contentType.ID); 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/CustomPowerSlice/BlocksSlice.cs: -------------------------------------------------------------------------------- 1 | using AlloyTemplates.Models.Blocks; 2 | using EPiServer.ServiceLocation; 3 | using EPiServer.Shell.ContentQuery; 4 | using PowerSlice; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Web; 9 | 10 | namespace AlloyTemplates.MySlice 11 | { 12 | [ServiceConfiguration(typeof(IContentQuery)), ServiceConfiguration(typeof(IContentSlice))] 13 | public class BlocksSlice : ContentSliceBase 14 | { 15 | public override string Name 16 | { 17 | get { return "Blocks"; } 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/CustomPowerSlice/EverythingSlice.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Core; 2 | using EPiServer.ServiceLocation; 3 | using EPiServer.Shell.ContentQuery; 4 | using PowerSlice; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Web; 9 | 10 | namespace AlloyTemplates 11 | { 12 | [ServiceConfiguration(typeof(IContentQuery)), ServiceConfiguration(typeof(IContentSlice))] 13 | public class EverythingSlice : ContentSliceBase 14 | { 15 | public override string Name 16 | { 17 | get { return "Everything"; } 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/CustomPowerSlice/MyPagesSlice.cs: -------------------------------------------------------------------------------- 1 | using AlloyTemplates.Models.Pages; 2 | using EPiServer.Cms.Shell.UI.Rest.ContentQuery; 3 | using EPiServer.Core; 4 | using EPiServer.Find; 5 | using EPiServer.ServiceLocation; 6 | using EPiServer.Shell.ContentQuery; 7 | using Microsoft.AspNetCore.Http; 8 | using PowerSlice; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using System.Web; 13 | 14 | namespace AlloyTemplates.MySlice 15 | { 16 | [ServiceConfiguration(typeof(IContentQuery)), ServiceConfiguration(typeof(IContentSlice))] 17 | public class MyPagesSlice : ContentSliceBase 18 | { 19 | private readonly IHttpContextAccessor _httpContextAccessor; 20 | public MyPagesSlice(IHttpContextAccessor httpContextAccessor) 21 | { 22 | _httpContextAccessor = httpContextAccessor; 23 | } 24 | public override string Name 25 | { 26 | get { return "My Pages"; } 27 | } 28 | protected override ITypeSearch Filter(ITypeSearch searchRequest, ContentQueryParameters parameters) 29 | { 30 | var userName = _httpContextAccessor.HttpContext.User.Identity.Name; 31 | return searchRequest.Filter(x => x.MatchTypeHierarchy(typeof(IChangeTrackable)) & ((IChangeTrackable)x).CreatedBy.Match(userName)); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/CustomPowerSlice/PagesSlice.cs: -------------------------------------------------------------------------------- 1 | using AlloyTemplates.Models.Pages; 2 | using EPiServer.ServiceLocation; 3 | using EPiServer.Shell.ContentQuery; 4 | using PowerSlice; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Web; 9 | 10 | namespace AlloyTemplates.MySlice 11 | { 12 | [ServiceConfiguration(typeof(IContentQuery)), ServiceConfiguration(typeof(IContentSlice))] 13 | public class PagesSlice : ContentSliceBase 14 | { 15 | public override string Name 16 | { 17 | get { return "Pages"; } 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Extensions/HttpContextExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Threading.Tasks; 7 | 8 | namespace EPiServer.Templates.Alloy.Mvc.Extensions 9 | { 10 | public static class HttpContextExtensions 11 | { 12 | private const string NullIpAddress = "::1"; 13 | private static bool? _isLocalRequest = null; 14 | 15 | public static bool IsLocalRequest(this HttpContext httpContext) 16 | { 17 | if (!_isLocalRequest.HasValue) 18 | { 19 | var connection = httpContext.Connection; 20 | 21 | _isLocalRequest = connection.RemoteIpAddress.IsSet() ? connection.LocalIpAddress.IsSet() 22 | //Is local is same as remote, then we are local 23 | ? connection.RemoteIpAddress.Equals(connection.LocalIpAddress) 24 | //else we are remote if the remote IP address is not a loopback address 25 | : IPAddress.IsLoopback(connection.RemoteIpAddress) 26 | : true; 27 | } 28 | 29 | return _isLocalRequest.Value; 30 | } 31 | 32 | private static bool IsSet(this IPAddress address) 33 | { 34 | return address != null && address.ToString() != NullIpAddress; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Extensions/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using AlloyMvcTemplates.Business.Rendering; 2 | using AlloyTemplates; 3 | using AlloyTemplates.Business; 4 | using AlloyTemplates.Business.Channels; 5 | using EPiServer.Web; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.Razor; 8 | using Microsoft.Extensions.DependencyInjection; 9 | 10 | namespace AlloyMvcTemplates.Extensions 11 | { 12 | public static class ServiceCollectionExtensions 13 | { 14 | public static void AddAlloy(this IServiceCollection services) 15 | { 16 | services.Configure(options => 17 | { 18 | options.ViewLocationExpanders.Add(new SiteViewEngineLocationExpander()); 19 | }); 20 | 21 | services.Configure(displayOption => 22 | { 23 | displayOption.Add("full", "/displayoptions/full", Global.ContentAreaTags.FullWidth, "", "epi-icon__layout--full"); 24 | displayOption.Add("wide", "/displayoptions/wide", Global.ContentAreaTags.TwoThirdsWidth, "", "epi-icon__layout--two-thirds"); 25 | displayOption.Add("narrow", "/displayoptions/narrow", Global.ContentAreaTags.OneThirdWidth, "", "epi-icon__layout--one-third"); 26 | }); 27 | 28 | services.Configure(options => 29 | { 30 | options.Filters.Add(); 31 | }); 32 | 33 | services.AddDisplayResolutions(); 34 | services.AddDetection(); 35 | } 36 | 37 | private static void AddDisplayResolutions(this IServiceCollection services) 38 | { 39 | services.AddSingleton(); 40 | services.AddSingleton(); 41 | services.AddSingleton(); 42 | services.AddSingleton(); 43 | } 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Extensions/ViewContextExtension.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Web; 2 | using Microsoft.AspNetCore.Mvc.Controllers; 3 | using Microsoft.AspNetCore.Mvc.Rendering; 4 | using Microsoft.Extensions.DependencyInjection; 5 | 6 | namespace AlloyTemplates.Helpers 7 | { 8 | /// 9 | /// Extension methods on request Context such as et/Set Node, Lang, Controller 10 | /// 11 | public static class ViewContextExtension 12 | { 13 | 14 | /// 15 | /// Determine if the the controller is in the preview mode. 16 | /// 17 | /// 18 | /// 19 | public static bool IsPreviewMode(this ViewContext viewContext) 20 | { 21 | return viewContext.IsInEditMode() && (viewContext.ActionDescriptor as ControllerActionDescriptor)?.ControllerName == "Preview"; 22 | } 23 | 24 | /// 25 | /// Determines if the request context is in edit mode. 26 | /// 27 | /// The request context 28 | /// trueIf the context is in edit mode; otherwise false 29 | public static bool IsInEditMode(this ViewContext viewContext) 30 | { 31 | var mode = viewContext.HttpContext.RequestServices.GetRequiredService().CurrentMode; 32 | return mode == ContextMode.Edit || mode == ContextMode.Preview; 33 | } 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Helpers/CategorizableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using EPiServer.Core; 4 | using EPiServer.DataAbstraction; 5 | using EPiServer.ServiceLocation; 6 | 7 | namespace AlloyTemplates.Helpers 8 | { 9 | /// 10 | /// Provides extension methods for categorizable content 11 | /// 12 | /// ICategorizable content includes for example pages and blocks. 13 | public static class CategorizableExtensions 14 | { 15 | /// 16 | /// Returns the CSS classes (if any) associated with the theme(s) of the content, as decided by its categories 17 | /// 18 | /// 19 | /// CSS classes associated with the content's theme(s), or an empty string array if no theme is applicable 20 | /// Content's categorization may map to more than one theme. This method assumes there are website categories called "Meet", "Track", and "Plan" 21 | public static string[] GetThemeCssClassNames(this ICategorizable content) 22 | { 23 | if (content.Category == null) 24 | { 25 | return new string[0]; 26 | } 27 | 28 | var cssClasses = new HashSet(); // Although with some overhead, a HashSet allows us to ensure we never add a CSS class more than once 29 | var categoryRepository = ServiceLocator.Current.GetInstance(); 30 | 31 | foreach (var categoryName in content.Category.Select(category => categoryRepository.Get(category)?.Name.ToLower())) 32 | { 33 | switch (categoryName) 34 | { 35 | case "meet": 36 | cssClasses.Add("theme1"); 37 | break; 38 | case "track": 39 | cssClasses.Add("theme2"); 40 | break; 41 | case "plan": 42 | cssClasses.Add("theme3"); 43 | break; 44 | } 45 | } 46 | 47 | return cssClasses.ToArray(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Helpers/UrlHelpers.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Core; 2 | using EPiServer.ServiceLocation; 3 | using EPiServer.Web.Routing; 4 | using EPiServer; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace AlloyTemplates.Helpers 9 | { 10 | public static class UrlHelpers 11 | { 12 | /// 13 | /// Returns the target URL for a ContentReference. Respects the page's shortcut setting 14 | /// so if the page is set as a shortcut to another page or an external URL that URL 15 | /// will be returned. 16 | /// 17 | public static string PageLinkUrl(this IUrlHelper urlHelper, ContentReference contentLink) 18 | { 19 | if(ContentReference.IsNullOrEmpty(contentLink)) 20 | { 21 | return string.Empty; 22 | } 23 | 24 | var contentLoader = ServiceLocator.Current.GetInstance(); 25 | var page = contentLoader.Get(contentLink); 26 | 27 | return PageLinkUrl(urlHelper, page); 28 | } 29 | 30 | /// 31 | /// Returns the target URL for a page. Respects the page's shortcut setting 32 | /// so if the page is set as a shortcut to another page or an external URL that URL 33 | /// will be returned. 34 | /// 35 | public static string PageLinkUrl(this IUrlHelper urlHelper, PageData page) 36 | { 37 | var urlResolver = urlHelper.ActionContext.HttpContext.RequestServices.GetRequiredService(); 38 | switch (page.LinkType) 39 | { 40 | case PageShortcutType.Normal: 41 | case PageShortcutType.FetchData: 42 | return urlResolver.GetUrl(page.ContentLink); 43 | 44 | case PageShortcutType.Shortcut: 45 | var shortcutProperty = page.Property["PageShortcutLink"] as PropertyPageReference; 46 | if (shortcutProperty != null && !ContentReference.IsNullOrEmpty(shortcutProperty.ContentLink)) 47 | { 48 | return urlHelper.PageLinkUrl(shortcutProperty.ContentLink); 49 | } 50 | break; 51 | 52 | case PageShortcutType.External: 53 | return page.LinkURL; 54 | } 55 | return string.Empty; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Infrastructure/AdministratorRegistrationPageMiddleware.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.ServiceLocation; 2 | using EPiServer.Shell.Security; 3 | using EPiServer.Templates.Alloy.Mvc.Extensions; 4 | using EPiServer.Web; 5 | using Microsoft.AspNetCore.Http; 6 | using System; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | 10 | namespace AlloyMvcTemplates.Infrastructure 11 | { 12 | public class AdministratorRegistrationPageMiddleware 13 | { 14 | private readonly RequestDelegate _next; 15 | 16 | private static bool _isFirstRequest = true; 17 | private const string RegisterUrl = "/Register"; 18 | 19 | public static bool? IsEnabled { get; set; } 20 | 21 | public AdministratorRegistrationPageMiddleware(RequestDelegate next) 22 | { 23 | _next = next; 24 | } 25 | 26 | 27 | public async Task InvokeAsync(HttpContext context) 28 | { 29 | if (!_isFirstRequest) 30 | { 31 | await _next(context); 32 | return; 33 | } 34 | 35 | _isFirstRequest = false; 36 | 37 | if (!context.IsLocalRequest() || context.Request.Path != "/") 38 | { 39 | 40 | await _next(context); 41 | return; 42 | } 43 | 44 | if (!IsEnabled.HasValue) 45 | { 46 | IsEnabled = await UserDatabaseIsEmpty(); 47 | } 48 | 49 | if (IsEnabled.Value) 50 | { 51 | context.Response.Redirect(RegisterUrl); 52 | } 53 | 54 | await _next(context); 55 | } 56 | 57 | 58 | private async Task UserDatabaseIsEmpty() 59 | { 60 | var provider = ServiceLocator.Current.GetInstance(); 61 | await foreach(var res in provider.GetAllUsersAsync(0, 1)) 62 | { 63 | return false; 64 | } 65 | return true; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Infrastructure/RegisterFirstAdminWithLocalRequestAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using AlloyTemplates; 3 | using Microsoft.AspNetCore.Mvc.Filters; 4 | using Microsoft.AspNetCore.Mvc; 5 | 6 | namespace AlloyMvcTemplates.Infrastructure 7 | { 8 | [AttributeUsage(AttributeTargets.Class, Inherited = true)] 9 | public class RegisterFirstAdminWithLocalRequestAttribute : Attribute, IAuthorizationFilter 10 | { 11 | public void OnAuthorization(AuthorizationFilterContext context) 12 | { 13 | if (AdministratorRegistrationPageMiddleware.IsEnabled == false) 14 | { 15 | context.Result = new NotFoundResult(); 16 | return; 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/InternalServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Framework.Hosting; 2 | using EPiServer.Framework.Web.Resources; 3 | using EPiServer.Web.Hosting; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using System.IO; 6 | 7 | namespace AlloyMvcTemplates 8 | { 9 | public static class InternalServiceCollectionExtensions 10 | { 11 | public static IServiceCollection AddUIMappedFileProviders(this IServiceCollection services, string applicationRootPath, string uiSolutionRelativePath) 12 | { 13 | services.Configure(o => o.Debug = true); 14 | 15 | var uiSolutionFolder = Path.Combine(applicationRootPath, uiSolutionRelativePath); 16 | EnsureDictionary(new DirectoryInfo(Path.Combine(applicationRootPath, "modules/_protected"))); 17 | services.Configure(c => 18 | { 19 | c.BasePathFileProviders.Add(new MappingPhysicalFileProvider("/EPiServer/PowerSlice", string.Empty, Path.Combine(uiSolutionFolder, "PowerSlice"))); 20 | }); 21 | return services; 22 | } 23 | 24 | private static void EnsureDictionary(DirectoryInfo directoryInfo) 25 | { 26 | if (!directoryInfo.Parent.Exists) 27 | { 28 | EnsureDictionary(directoryInfo.Parent); 29 | } 30 | 31 | if (!directoryInfo.Exists) 32 | { 33 | directoryInfo.Create(); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Blocks/ButtonBlock.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using EPiServer.DataAbstraction; 3 | using EPiServer; 4 | 5 | namespace AlloyTemplates.Models.Blocks 6 | { 7 | /// 8 | /// Used to insert a link which is styled as a button 9 | /// 10 | [SiteContentType(GUID = "426CF12F-1F01-4EA0-922F-0778314DDAF0")] 11 | [SiteImageUrl] 12 | public class ButtonBlock : SiteBlockData 13 | { 14 | [Display(Order = 1, GroupName = SystemTabNames.Content)] 15 | [Required] 16 | public virtual string ButtonText { get; set; } 17 | 18 | [Display(Order = 2, GroupName = SystemTabNames.Content)] 19 | [Required] 20 | public virtual Url ButtonLink { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Blocks/ContactBlock.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using EPiServer.Core; 3 | using EPiServer.DataAbstraction; 4 | using EPiServer.DataAnnotations; 5 | using EPiServer.Web; 6 | using EPiServer; 7 | 8 | namespace AlloyTemplates.Models.Blocks 9 | { 10 | /// 11 | /// Used to present contact information with a call-to-action link 12 | /// 13 | /// Actual contact details are retrieved from a contact page specified using the ContactPageLink property 14 | [SiteContentType(GUID = "7E932EAF-6BC2-4753-902A-8670EDC5F363")] 15 | [SiteImageUrl] 16 | public class ContactBlock : SiteBlockData 17 | { 18 | [Display( 19 | GroupName = SystemTabNames.Content, 20 | Order = 1)] 21 | [CultureSpecific] 22 | [UIHint(UIHint.Image)] 23 | public virtual ContentReference Image { get; set; } 24 | 25 | [Display( 26 | GroupName = SystemTabNames.Content, 27 | Order = 2)] 28 | [CultureSpecific] 29 | public virtual string Heading { get; set; } 30 | 31 | /// 32 | /// Gets or sets the contact page from which contact information should be retrieved 33 | /// 34 | [Display( 35 | GroupName = SystemTabNames.Content, 36 | Order = 3)] 37 | [UIHint(Global.SiteUIHints.Contact)] 38 | public virtual PageReference ContactPageLink { get; set; } 39 | 40 | [Display( 41 | GroupName = SystemTabNames.Content, 42 | Order = 4)] 43 | [CultureSpecific] 44 | public virtual string LinkText { get; set; } 45 | 46 | [Display( 47 | GroupName = SystemTabNames.Content, 48 | Order = 5)] 49 | [CultureSpecific] 50 | public virtual Url LinkUrl { get; set; } 51 | } 52 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Blocks/EditorialBlock.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using EPiServer.Core; 3 | using EPiServer.DataAbstraction; 4 | using EPiServer.DataAnnotations; 5 | using EPiServer.Shell; 6 | 7 | namespace AlloyTemplates.Models.Blocks 8 | { 9 | /// 10 | /// Used to insert editorial content edited using a rich-text editor 11 | /// 12 | [SiteContentType( 13 | GUID = "67F617A4-2175-4360-975E-75EDF2B924A7", 14 | GroupName = SystemTabNames.Content)] 15 | [SiteImageUrl] 16 | public class EditorialBlock : SiteBlockData 17 | { 18 | [Display(GroupName = SystemTabNames.Content)] 19 | [CultureSpecific] 20 | public virtual XhtmlString MainBody { get; set; } 21 | } 22 | 23 | [UIDescriptorRegistration] 24 | public class EditorialBlockUIDescriptor : UIDescriptor 25 | { 26 | public EditorialBlockUIDescriptor() 27 | : base("editorial-block-icon") 28 | { 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Blocks/JumbotronBlock.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using EPiServer.DataAbstraction; 3 | using EPiServer.DataAnnotations; 4 | using EPiServer.Web; 5 | using EPiServer.Core; 6 | using EPiServer; 7 | 8 | namespace AlloyTemplates.Models.Blocks 9 | { 10 | /// 11 | /// Used for a primary message on a page, commonly used on start pages and landing pages 12 | /// 13 | [SiteContentType( 14 | GroupName = Global.GroupNames.Specialized, 15 | GUID = "9FD1C860-7183-4122-8CD4-FF4C55E096F9")] 16 | [SiteImageUrl] 17 | public class JumbotronBlock : SiteBlockData 18 | { 19 | [Display( 20 | GroupName = SystemTabNames.Content, 21 | Order = 1 22 | )] 23 | [CultureSpecific] 24 | [UIHint(UIHint.Image)] 25 | public virtual ContentReference Image { get; set; } 26 | 27 | /// 28 | /// Gets or sets a description for the image, for example used as the alt text for the image when rendered 29 | /// 30 | [Display( 31 | GroupName = SystemTabNames.Content, 32 | Order = 1 33 | )] 34 | [CultureSpecific] 35 | [UIHint(UIHint.Textarea)] 36 | public virtual string ImageDescription 37 | { 38 | get 39 | { 40 | var propertyValue = this["ImageDescription"] as string; 41 | 42 | // Return image description with fall back to the heading if no description has been specified 43 | return string.IsNullOrWhiteSpace(propertyValue) ? Heading : propertyValue; 44 | } 45 | set { this["ImageDescription"] = value; } 46 | } 47 | 48 | [Display( 49 | GroupName = SystemTabNames.Content, 50 | Order = 1 51 | )] 52 | [CultureSpecific] 53 | public virtual string Heading { get; set; } 54 | 55 | [Display( 56 | GroupName = SystemTabNames.Content, 57 | Order = 2 58 | )] 59 | [CultureSpecific] 60 | [UIHint(UIHint.Textarea)] 61 | public virtual string SubHeading { get; set; } 62 | 63 | [Display( 64 | GroupName = SystemTabNames.Content, 65 | Order = 3 66 | )] 67 | [CultureSpecific] 68 | [Required] 69 | public virtual string ButtonText { get; set; } 70 | 71 | //The link must be required as an anchor tag requires an href in order to be valid and focusable 72 | [Display( 73 | GroupName = SystemTabNames.Content, 74 | Order = 4 75 | )] 76 | [CultureSpecific] 77 | [Required] 78 | public virtual Url ButtonLink { get; set; } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Blocks/PageListBlock.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.ComponentModel.DataAnnotations; 3 | using EPiServer.Core; 4 | using EPiServer.DataAbstraction; 5 | using EPiServer.DataAnnotations; 6 | using EPiServer.Filters; 7 | 8 | namespace AlloyTemplates.Models.Blocks 9 | { 10 | /// 11 | /// Used to insert a list of pages, for example a news list 12 | /// 13 | [SiteContentType(GUID = "30685434-33DE-42AF-88A7-3126B936AEAD")] 14 | [SiteImageUrl] 15 | public class PageListBlock : SiteBlockData 16 | { 17 | [Display( 18 | GroupName = SystemTabNames.Content, 19 | Order = 1)] 20 | [CultureSpecific] 21 | public virtual string Heading { get; set; } 22 | 23 | [Display( 24 | GroupName = SystemTabNames.Content, 25 | Order = 2)] 26 | [DefaultValue(false)] 27 | public virtual bool IncludePublishDate { get; set; } 28 | 29 | /// 30 | /// Gets or sets whether a page introduction/description should be included in the list 31 | /// 32 | [Display( 33 | GroupName = SystemTabNames.Content, 34 | Order = 3)] 35 | [DefaultValue(true)] 36 | public virtual bool IncludeIntroduction { get; set; } 37 | 38 | [Display( 39 | GroupName = SystemTabNames.Content, 40 | Order = 4)] 41 | [DefaultValue(3)] 42 | [Required] 43 | public virtual int Count { get; set; } 44 | 45 | [Display( 46 | GroupName = SystemTabNames.Content, 47 | Order = 4)] 48 | [DefaultValue(FilterSortOrder.PublishedDescending)] 49 | [UIHint("SortOrder")] 50 | [BackingType(typeof(PropertyNumber))] 51 | public virtual FilterSortOrder SortOrder { get; set; } 52 | 53 | [Display( 54 | GroupName = SystemTabNames.Content, 55 | Order = 5)] 56 | [Required] 57 | public virtual PageReference Root { get; set; } 58 | 59 | [Display( 60 | GroupName = SystemTabNames.Content, 61 | Order = 6)] 62 | public virtual PageType PageTypeFilter{get; set;} 63 | 64 | [Display( 65 | GroupName = SystemTabNames.Content, 66 | Order = 7)] 67 | public virtual CategoryList CategoryFilter { get; set; } 68 | 69 | [Display( 70 | GroupName = SystemTabNames.Content, 71 | Order = 8)] 72 | public virtual bool Recursive { get; set; } 73 | 74 | #region IInitializableContent 75 | 76 | /// 77 | /// Sets the default property values on the content data. 78 | /// 79 | /// Type of the content. 80 | public override void SetDefaultValues(ContentType contentType) 81 | { 82 | base.SetDefaultValues(contentType); 83 | 84 | Count = 3; 85 | IncludeIntroduction = true; 86 | IncludePublishDate = false; 87 | SortOrder = FilterSortOrder.PublishedDescending; 88 | } 89 | 90 | #endregion 91 | } 92 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Blocks/SiteBlockData.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace AlloyTemplates.Models.Blocks 3 | { 4 | /// 5 | /// Base class for all block types on the site 6 | /// 7 | public abstract class SiteBlockData : EPiServer.Core.BlockData 8 | { 9 | } 10 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Blocks/SiteLogotypeBlock.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using EPiServer.Core; 3 | using EPiServer.DataAnnotations; 4 | using EPiServer.Shell.ObjectEditing; 5 | using EPiServer.Web; 6 | using EPiServer; 7 | 8 | namespace AlloyTemplates.Models.Blocks 9 | { 10 | /// 11 | /// Used to provide a composite property on the start page to set site logotype settings 12 | /// 13 | [SiteContentType( 14 | GUID = "09854019-91A5-4B93-8623-17F038346001", 15 | AvailableInEditMode = false)] // Should not be created and added to content areas by editors, the SiteLogotypeBlock is only used as a property type 16 | [SiteImageUrl] 17 | public class SiteLogotypeBlock : SiteBlockData 18 | { 19 | /// 20 | /// Gets the site logotype URL 21 | /// 22 | /// If not specified a default logotype will be used 23 | [DefaultDragAndDropTarget] 24 | [UIHint(UIHint.Image)] 25 | public virtual Url Url 26 | { 27 | get 28 | { 29 | var url = this.GetPropertyValue(b => b.Url); 30 | 31 | return url == null || url.IsEmpty() 32 | ? new Url("/gfx/logotype.png") 33 | : url; 34 | } 35 | set 36 | { 37 | this.SetPropertyValue(b => b.Url, value); 38 | } 39 | } 40 | 41 | [CultureSpecific] 42 | public virtual string Title { get; set; } 43 | } 44 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Blocks/TeaserBlock.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using EPiServer.Core; 3 | using EPiServer.DataAbstraction; 4 | using EPiServer.DataAnnotations; 5 | using EPiServer.Web; 6 | 7 | namespace AlloyTemplates.Models.Blocks 8 | { 9 | /// 10 | /// Used to provide a stylized entry point to a page on the site 11 | /// 12 | [SiteContentType(GUID = "EB67A99A-E239-41B8-9C59-20EAA5936047")] // BEST PRACTICE TIP: Always assign a GUID explicitly when creating a new block type 13 | [SiteImageUrl] // Use site's default thumbnail 14 | public class TeaserBlock : SiteBlockData 15 | { 16 | [CultureSpecific] 17 | [Required(AllowEmptyStrings = false)] 18 | [Display( 19 | GroupName = SystemTabNames.Content, 20 | Order = 1)] 21 | public virtual string Heading { get; set; } 22 | 23 | [CultureSpecific] 24 | [Required(AllowEmptyStrings = false)] 25 | [Display( 26 | GroupName = SystemTabNames.Content, 27 | Order = 2)] 28 | [UIHint(UIHint.Textarea)] 29 | public virtual string Text { get; set; } 30 | 31 | [CultureSpecific] 32 | [Required(AllowEmptyStrings = false)] 33 | [UIHint(UIHint.Image)] 34 | [Display( 35 | GroupName = SystemTabNames.Content, 36 | Order = 3)] 37 | public virtual ContentReference Image { get; set; } 38 | 39 | [Display( 40 | GroupName = SystemTabNames.Content, 41 | Order = 4)] 42 | public virtual PageReference Link { get; set; } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Blocks/_ReadMe.txt: -------------------------------------------------------------------------------- 1 | This folder contains all block types. 2 | 3 | Blocks should be named with a suffix of "Block", such as "TeaserBlock" or "NewsListBlock". 4 | 5 | Default block controls should be named with a suffix of "Control", 6 | such as "TeaserBlockControl" or "NewsListBlockControl". -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/HeadlessContent/IngredientBlock.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using AlloyTemplates.Business.Rendering; 3 | using AlloyTemplates.Models; 4 | using EPiServer.Core; 5 | using EPiServer.DataAbstraction; 6 | using EPiServer.DataAnnotations; 7 | 8 | namespace AlloyMvcTemplates.Models.HeadlessContent 9 | { 10 | [SiteContentType(GUID = "22F617A4-2175-4360-975E-75EDF2B924A7", GroupName = "Headless", DisplayName = "[Headless] Ingredient")] 11 | [SiteImageUrl] 12 | public class IngredientBlock : BlockData, IContainerPage 13 | { 14 | [Display(GroupName = SystemTabNames.Content)] 15 | [CultureSpecific] 16 | public virtual XhtmlString MainBody { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/HeadlessContent/RecipeBlock.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using AlloyTemplates.Business.Rendering; 3 | using AlloyTemplates.Models; 4 | using AlloyTemplates.Models.Blocks; 5 | using EPiServer.Core; 6 | using EPiServer.DataAbstraction; 7 | using EPiServer.DataAnnotations; 8 | 9 | namespace AlloyMvcTemplates.Models.HeadlessContent 10 | { 11 | [SiteContentType(GUID = "11F617A4-2175-4360-975E-75EDF2B924A7", GroupName = "Headless", DisplayName = "[Headless] Recipe")] 12 | [SiteImageUrl] 13 | [AvailableContentTypes(Availability.Specific, Include = new [] {typeof(IngredientBlock)})] 14 | public class RecipeBlock : BlockData, IContainerPage 15 | { 16 | [Display(GroupName = SystemTabNames.Content)] 17 | [CultureSpecific] 18 | public virtual XhtmlString MainBody { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/LoginViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace AlloyMvcTemplates.Models 4 | { 5 | public class LoginViewModel 6 | { 7 | [Required] 8 | public string Username { get; set; } 9 | [Required] 10 | public string Password { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Media/GenericMedia.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Core; 2 | using EPiServer.DataAnnotations; 3 | using System; 4 | 5 | namespace AlloyTemplates.Models.Media 6 | { 7 | [ContentType(GUID = "EE3BD195-7CB0-4756-AB5F-E5E223CD9820")] 8 | public class GenericMedia : MediaData 9 | { 10 | /// 11 | /// Gets or sets the description. 12 | /// 13 | public virtual String Description { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Media/ImageFile.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Core; 2 | using EPiServer.DataAnnotations; 3 | using EPiServer.Framework.DataAnnotations; 4 | 5 | namespace AlloyTemplates.Models.Media 6 | { 7 | [ContentType(GUID = "0A89E464-56D4-449F-AEA8-2BF774AB8730")] 8 | [MediaDescriptor(ExtensionString = "jpg,jpeg,jpe,ico,gif,bmp,png,tiff")] 9 | public class ImageFile : ImageData 10 | { 11 | /// 12 | /// Gets or sets the copyright. 13 | /// 14 | /// 15 | /// The copyright. 16 | /// 17 | public virtual string Copyright { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Media/VectorImageFile.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Core; 2 | using EPiServer.DataAnnotations; 3 | using EPiServer.Framework.Blobs; 4 | using EPiServer.Framework.DataAnnotations; 5 | 6 | namespace AlloyMvcTemplates.Models.Media 7 | { 8 | [ContentType(GUID = "F522B459-EB27-462C-B216-989FC7FF9448")] 9 | [MediaDescriptor(ExtensionString = "svg")] 10 | public class VectorImageFile : ImageData 11 | { 12 | /// 13 | /// Gets the generated thumbnail for this media. 14 | /// 15 | public override Blob Thumbnail 16 | { 17 | get { return BinaryData; } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Media/VideoFile.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using EPiServer.Core; 3 | using EPiServer.DataAnnotations; 4 | using EPiServer.Framework.DataAnnotations; 5 | using EPiServer.Web; 6 | 7 | namespace AlloyTemplates.Models.Media 8 | { 9 | [ContentType(GUID = "85468104-E06F-47E5-A317-FC9B83D3CBA6")] 10 | [MediaDescriptor(ExtensionString = "flv,mp4,webm")] 11 | public class VideoFile : VideoData 12 | { 13 | /// 14 | /// Gets or sets the copyright. 15 | /// 16 | public virtual string Copyright { get; set; } 17 | 18 | /// 19 | /// Gets or sets the URL to the preview image. 20 | /// 21 | [UIHint(UIHint.Image)] 22 | public virtual ContentReference PreviewImage { get; set; } 23 | } 24 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Pages/ArticlePage.cs: -------------------------------------------------------------------------------- 1 | namespace AlloyTemplates.Models.Pages 2 | { 3 | /// 4 | /// Used primarily for publishing news articles on the website 5 | /// 6 | [SiteContentType( 7 | GroupName = Global.GroupNames.News, 8 | GUID = "AEECADF2-3E89-4117-ADEB-F8D43565D2F4")] 9 | [SiteImageUrl(Global.StaticGraphicsFolderPath + "page-type-thumbnail-article.png")] 10 | public class ArticlePage : StandardPage 11 | { 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Pages/ContactPage.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using AlloyTemplates.Business.Rendering; 3 | using EPiServer.Web; 4 | using EPiServer.Core; 5 | 6 | namespace AlloyTemplates.Models.Pages 7 | { 8 | /// 9 | /// Represents contact details for a contact person 10 | /// 11 | [SiteContentType( 12 | GUID = "F8D47655-7B50-4319-8646-3369BA9AF05B", 13 | GroupName = Global.GroupNames.Specialized)] 14 | [SiteImageUrl(Global.StaticGraphicsFolderPath + "page-type-thumbnail-contact.png")] 15 | public class ContactPage : SitePageData, IContainerPage 16 | { 17 | [Display(GroupName = Global.GroupNames.Contact)] 18 | [UIHint(UIHint.Image)] 19 | public virtual ContentReference Image { get; set; } 20 | 21 | [Display(GroupName = Global.GroupNames.Contact)] 22 | public virtual string Phone { get; set; } 23 | 24 | [Display(GroupName = Global.GroupNames.Contact)] 25 | [EmailAddress] 26 | public virtual string Email { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Pages/ContainerPage.cs: -------------------------------------------------------------------------------- 1 | using AlloyTemplates.Business.Rendering; 2 | 3 | namespace AlloyTemplates.Models.Pages 4 | { 5 | /// 6 | /// Used to logically group pages in the page tree 7 | /// 8 | [SiteContentType( 9 | GUID = "D178950C-D20E-4A46-90BD-5338B2424745", 10 | GroupName = Global.GroupNames.Specialized)] 11 | [SiteImageUrl] 12 | public class ContainerPage : SitePageData, IContainerPage 13 | { 14 | 15 | } 16 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Pages/IHasRelatedContent.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Core; 2 | 3 | namespace AlloyTemplates.Models.Pages 4 | { 5 | public interface IHasRelatedContent 6 | { 7 | ContentArea RelatedContentArea { get; } 8 | } 9 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Pages/ISearchPage.cs: -------------------------------------------------------------------------------- 1 | namespace AlloyTemplates.Models.Pages 2 | { 3 | /// 4 | /// Marker interface for search implementation 5 | /// 6 | public interface ISearchPage 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Pages/LandingPage.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using EPiServer.Core; 3 | using EPiServer.DataAbstraction; 4 | using EPiServer.DataAnnotations; 5 | 6 | namespace AlloyTemplates.Models.Pages 7 | { 8 | /// 9 | /// Used for campaign or landing pages, commonly used for pages linked in online advertising such as AdWords 10 | /// 11 | [SiteContentType( 12 | GUID = "DBED4258-8213-48DB-A11F-99C034172A54", 13 | GroupName = Global.GroupNames.Specialized)] 14 | [SiteImageUrl] 15 | public class LandingPage : SitePageData 16 | { 17 | [Display( 18 | GroupName = SystemTabNames.Content, 19 | Order=310)] 20 | [CultureSpecific] 21 | public virtual ContentArea MainContentArea { get; set; } 22 | 23 | public override void SetDefaultValues(ContentType contentType) 24 | { 25 | base.SetDefaultValues(contentType); 26 | 27 | HideSiteFooter = true; 28 | HideSiteHeader = true; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Pages/NewsPage.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using EPiServer.DataAbstraction; 3 | using EPiServer.Filters; 4 | using EPiServer.Framework.Localization; 5 | using EPiServer.ServiceLocation; 6 | using AlloyTemplates.Business; 7 | using AlloyTemplates.Models.Blocks; 8 | 9 | namespace AlloyTemplates.Models.Pages 10 | { 11 | /// 12 | /// Presents a news section including a list of the most recent articles on the site 13 | /// 14 | [SiteContentType(GUID = "638D8271-5CA3-4C72-BABC-3E8779233263")] 15 | [SiteImageUrl] 16 | public class NewsPage : StandardPage 17 | { 18 | [Display( 19 | GroupName = SystemTabNames.Content, 20 | Order = 305)] 21 | public virtual PageListBlock NewsList { get; set; } 22 | 23 | public override void SetDefaultValues(ContentType contentType) 24 | { 25 | base.SetDefaultValues(contentType); 26 | 27 | NewsList.Count = 20; 28 | NewsList.Heading = ServiceLocator.Current.GetInstance().GetString("/newspagetemplate/latestnews"); 29 | NewsList.IncludeIntroduction = true; 30 | NewsList.IncludePublishDate = true; 31 | NewsList.Recursive = true; 32 | NewsList.PageTypeFilter = typeof(ArticlePage).GetPageType(); 33 | NewsList.SortOrder = FilterSortOrder.PublishedDescending; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Pages/ProductPage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | using AlloyTemplates.Models.Blocks; 4 | using EPiServer.Core; 5 | using EPiServer.DataAbstraction; 6 | using EPiServer.DataAnnotations; 7 | 8 | namespace AlloyTemplates.Models.Pages 9 | { 10 | /// 11 | /// Used to present a single product 12 | /// 13 | [SiteContentType( 14 | GUID = "17583DCD-3C11-49DD-A66D-0DEF0DD601FC", 15 | GroupName = Global.GroupNames.Products)] 16 | [SiteImageUrl(Global.StaticGraphicsFolderPath + "page-type-thumbnail-product.png")] 17 | [AvailableContentTypes( 18 | Availability = Availability.Specific, 19 | IncludeOn = new[] { typeof(StartPage) })] 20 | public class ProductPage : StandardPage, IHasRelatedContent 21 | { 22 | [Display( 23 | GroupName = SystemTabNames.Content, 24 | Order = 330)] 25 | [CultureSpecific] 26 | [AllowedTypes(new[] { typeof(IContentData) },new[] { typeof(JumbotronBlock) })] 27 | public virtual ContentArea RelatedContentArea { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Pages/SearchPage.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using AlloyTemplates.Models.Blocks; 3 | using EPiServer.Core; 4 | using EPiServer.DataAbstraction; 5 | using EPiServer.DataAnnotations; 6 | 7 | namespace AlloyTemplates.Models.Pages 8 | { 9 | /// 10 | /// Used to provide on-site search 11 | /// 12 | [SiteContentType( 13 | GUID = "AAC25733-1D21-4F82-B031-11E626C91E30", 14 | GroupName = Global.GroupNames.Specialized)] 15 | [SiteImageUrl] 16 | public class SearchPage : SitePageData, IHasRelatedContent, ISearchPage 17 | { 18 | [Display( 19 | GroupName = SystemTabNames.Content, 20 | Order = 310)] 21 | [CultureSpecific] 22 | [AllowedTypes(new[] { typeof(IContentData) }, new[] { typeof(JumbotronBlock) })] 23 | public virtual ContentArea RelatedContentArea { get; set; } 24 | } 25 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Pages/StandardPage.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Core; 2 | using EPiServer.DataAbstraction; 3 | using EPiServer.DataAnnotations; 4 | using System.ComponentModel.DataAnnotations; 5 | 6 | namespace AlloyTemplates.Models.Pages 7 | { 8 | /// 9 | /// Used for the pages mainly consisting of manually created content such as text, images, and blocks 10 | /// 11 | [SiteContentType(GUID = "9CCC8A41-5C8C-4BE0-8E73-520FF3DE8267")] 12 | [SiteImageUrl(Global.StaticGraphicsFolderPath + "page-type-thumbnail-standard.png")] 13 | public class StandardPage : SitePageData 14 | { 15 | [Display( 16 | GroupName = SystemTabNames.Content, 17 | Order = 310)] 18 | [CultureSpecific] 19 | public virtual XhtmlString MainBody { get; set; } 20 | 21 | [Display( 22 | GroupName = SystemTabNames.Content, 23 | Order = 320)] 24 | public virtual ContentArea MainContentArea { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Pages/_ReadMe.txt: -------------------------------------------------------------------------------- 1 | This folder contains all page types. 2 | 3 | Pages should be named with a suffix of "Page", such as "StandardPage" or "ProductPage". 4 | 5 | Default page templates should be named with a suffix of "Template", 6 | such as "StandardPageTemplate" or "ProductPageTemplate". 7 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/Register/RegisterViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace AlloyTemplates.Models 4 | { 5 | public class RegisterViewModel 6 | { 7 | [Required] 8 | [Display(Name = "Username")] 9 | [RegularExpression(@"^[a-zA-Z0-9_-]+$", ErrorMessage = "Username can only contain letters a-z, numbers, underscores and hyphens.")] 10 | [StringLength(20, ErrorMessage ="The {0} field can not be more than {1} characters long.")] 11 | public string Username { get; set; } 12 | 13 | [Required] 14 | [EmailAddress] 15 | [Display(Name = "Email")] 16 | public string Email { get; set; } 17 | 18 | [Required] 19 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 20 | [DataType(DataType.Password)] 21 | [Display(Name = "Password")] 22 | public string Password { get; set; } 23 | 24 | [DataType(DataType.Password)] 25 | [Display(Name = "Confirm password")] 26 | [System.ComponentModel.DataAnnotations.Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] 27 | public string ConfirmPassword { get; set; } 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/SiteContentType.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.DataAnnotations; 2 | 3 | namespace AlloyTemplates.Models 4 | { 5 | /// 6 | /// Attribute used for site content types to set default attribute values 7 | /// 8 | public class SiteContentType : ContentTypeAttribute 9 | { 10 | public SiteContentType() 11 | { 12 | GroupName = Global.GroupNames.Default; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/SiteImageUrl.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.DataAnnotations; 2 | 3 | namespace AlloyTemplates.Models 4 | { 5 | /// 6 | /// Attribute to set the default thumbnail for site page and block types 7 | /// 8 | public class SiteImageUrl : ImageUrlAttribute 9 | { 10 | /// 11 | /// The parameterless constructor will initialize a SiteImageUrl attribute with a default thumbnail 12 | /// 13 | public SiteImageUrl() : base("/gfx/page-type-thumbnail.png") 14 | { 15 | 16 | } 17 | 18 | public SiteImageUrl(string path) : base(path) 19 | { 20 | 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/ViewModels/ContactBlockModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using AlloyTemplates.Models.Pages; 3 | using EPiServer.Web; 4 | using EPiServer.Core; 5 | using Microsoft.AspNetCore.Html; 6 | 7 | namespace AlloyTemplates.Models.ViewModels 8 | { 9 | public class ContactBlockModel 10 | { 11 | [UIHint(UIHint.Image)] 12 | public ContentReference Image { get; set; } 13 | public string Heading { get; set; } 14 | public string LinkText { get; set; } 15 | public IHtmlContent LinkUrl { get; set; } 16 | public bool ShowLink { get; set; } 17 | public ContactPage ContactPage { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/ViewModels/ContentRenderingErrorModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EPiServer; 3 | using EPiServer.Core; 4 | 5 | namespace AlloyTemplates.Models.ViewModels 6 | { 7 | public class ContentRenderingErrorModel 8 | { 9 | public ContentRenderingErrorModel(IContentData contentData, Exception exception) 10 | { 11 | var content = contentData as IContent; 12 | if(content != null) 13 | { 14 | ContentName = content.Name; 15 | } 16 | else 17 | { 18 | ContentName = string.Empty; 19 | } 20 | 21 | ContentTypeName = contentData.GetOriginalType().Name; 22 | 23 | Exception = exception; 24 | } 25 | 26 | public string ContentName { get; set; } 27 | public string ContentTypeName { get; set; } 28 | public Exception Exception { get; set; } 29 | } 30 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/ViewModels/IPageViewModel.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Core; 2 | using AlloyTemplates.Models.Pages; 3 | 4 | namespace AlloyTemplates.Models.ViewModels 5 | { 6 | /// 7 | /// Defines common characteristics for view models for pages, including properties used by layout files. 8 | /// 9 | /// 10 | /// Views which should handle several page types (T) can use this interface as model type rather than the 11 | /// concrete PageViewModel class, utilizing the that this interface is covariant. 12 | /// 13 | public interface IPageViewModel where T : SitePageData 14 | { 15 | T CurrentPage { get; } 16 | LayoutModel Layout { get; set; } 17 | IContent Section { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/ViewModels/ImageViewModel.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace AlloyTemplates.Models.ViewModels 3 | { 4 | /// 5 | /// View model for the image file 6 | /// 7 | public class ImageViewModel 8 | { 9 | /// 10 | /// Gets or sets the URL to the image. 11 | /// 12 | public string Url { get; set; } 13 | 14 | /// 15 | /// Gets or sets the name of the image. 16 | /// 17 | public string Name { get; set; } 18 | 19 | /// 20 | /// Gets or sets the copyright information of the image. 21 | /// 22 | public string Copyright { get; set; } 23 | } 24 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/ViewModels/LayoutModel.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.SpecializedProperties; 2 | using AlloyTemplates.Models.Blocks; 3 | using Microsoft.AspNetCore.Html; 4 | 5 | namespace AlloyTemplates.Models.ViewModels 6 | { 7 | public class LayoutModel 8 | { 9 | public SiteLogotypeBlock Logotype { get; set; } 10 | public IHtmlContent LogotypeLinkUrl { get; set; } 11 | public bool HideHeader { get; set; } 12 | public bool HideFooter { get; set; } 13 | public LinkItemCollection ProductPages { get; set; } 14 | public LinkItemCollection CompanyInformationPages { get; set; } 15 | public LinkItemCollection NewsPages { get; set; } 16 | public LinkItemCollection CustomerZonePages { get; set; } 17 | public bool LoggedIn { get; set; } 18 | public HtmlString LoginUrl { get; set; } 19 | public HtmlString LogOutUrl { get; set; } 20 | public HtmlString SearchActionUrl { get; set; } 21 | 22 | public bool IsInReadonlyMode {get;set;} 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/ViewModels/PageListModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EPiServer.Core; 3 | using AlloyTemplates.Models.Blocks; 4 | 5 | namespace AlloyTemplates.Models.ViewModels 6 | { 7 | public class PageListModel 8 | { 9 | public PageListModel(PageListBlock block) 10 | { 11 | Heading = block.Heading; 12 | ShowIntroduction = block.IncludeIntroduction; 13 | ShowPublishDate = block.IncludePublishDate; 14 | } 15 | public string Heading { get; set; } 16 | public IEnumerable Pages { get; set; } 17 | public bool ShowIntroduction { get; set; } 18 | public bool ShowPublishDate { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/ViewModels/PageViewModel.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Core; 2 | using AlloyTemplates.Models.Pages; 3 | 4 | namespace AlloyTemplates.Models.ViewModels 5 | { 6 | public class PageViewModel : IPageViewModel where T : SitePageData 7 | { 8 | public PageViewModel(T currentPage) 9 | { 10 | CurrentPage = currentPage; 11 | } 12 | 13 | public T CurrentPage { get; private set; } 14 | public LayoutModel Layout { get; set; } 15 | public IContent Section { get; set; } 16 | } 17 | 18 | public static class PageViewModel 19 | { 20 | /// 21 | /// Returns a PageViewModel of type . 22 | /// 23 | /// 24 | /// Convenience method for creating PageViewModels without having to specify the type as methods can use type inference while constructors cannot. 25 | /// 26 | public static PageViewModel Create(T page) where T : SitePageData 27 | { 28 | return new PageViewModel(page); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/ViewModels/PreviewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EPiServer.Core; 3 | using AlloyTemplates.Models.Pages; 4 | 5 | namespace AlloyTemplates.Models.ViewModels 6 | { 7 | public class PreviewModel : PageViewModel 8 | { 9 | public PreviewModel(SitePageData currentPage, IContent previewContent) 10 | : base(currentPage) 11 | { 12 | PreviewContent = previewContent; 13 | Areas = new List(); 14 | } 15 | 16 | public IContent PreviewContent { get; set; } 17 | public List Areas { get; set; } 18 | 19 | public class PreviewArea 20 | { 21 | public bool Supported { get; set; } 22 | public string AreaName { get; set; } 23 | public string AreaTag { get; set; } 24 | public ContentArea ContentArea { get; set; } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/ViewModels/SearchContentModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using AlloyTemplates.Models.Pages; 3 | 4 | namespace AlloyTemplates.Models.ViewModels 5 | { 6 | public class SearchContentModel : PageViewModel 7 | { 8 | public SearchContentModel(SearchPage currentPage) : base(currentPage) 9 | { 10 | } 11 | 12 | public bool SearchServiceDisabled { get; set; } 13 | public string SearchedQuery { get; set; } 14 | public int NumberOfHits { get; set; } 15 | public IEnumerable Hits { get; set; } 16 | 17 | public class SearchHit 18 | { 19 | public string Title { get; set; } 20 | public string Url { get; set; } 21 | public string Excerpt { get; set; } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Models/ViewModels/VideoViewModel.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace AlloyTemplates.Models.ViewModels 3 | { 4 | /// 5 | /// View model for the video file 6 | /// 7 | public class VideoViewModel 8 | { 9 | /// 10 | /// Gets or sets the URL to the video. 11 | /// 12 | public string Url { get; set; } 13 | 14 | /// 15 | /// Gets or sets the URL to a preview image for the video. 16 | /// 17 | public string PreviewImageUrl { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | using Serilog; 4 | using Serilog.Events; 5 | 6 | namespace EPiServer.Templates.Alloy.Mvc 7 | { 8 | public class Program 9 | { 10 | public static void Main(string[] args) 11 | { 12 | Log.Logger = new LoggerConfiguration() 13 | .MinimumLevel.Warning() 14 | .WriteTo.File("app_data/log.txt", rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: LogEventLevel.Warning) 15 | .WriteTo.Console() 16 | .CreateLogger(); 17 | 18 | CreateHostBuilder(args).Build().Run(); 19 | } 20 | 21 | public static IHostBuilder CreateHostBuilder(string[] args) => 22 | Host.CreateDefaultBuilder(args) 23 | .ConfigureCmsDefaults() 24 | .ConfigureLogging(logging => 25 | { 26 | logging.AddSerilog(); 27 | }) 28 | .UseSerilog() 29 | .ConfigureWebHostDefaults(webBuilder => 30 | { 31 | webBuilder.UseStartup(); 32 | }); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | [assembly: ComVisible(false)] 5 | [assembly: CLSCompliant(false)] 6 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:57729/", 7 | "sslPort": 44333 8 | } 9 | }, 10 | "profiles": { 11 | "Kestrel (Env: Development)": { 12 | "commandName": "Project", 13 | "launchBrowser": true, 14 | "applicationUrl": "http://localhost:8000/", 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "IIS Express (Env: Development)": { 20 | "commandName": "IISExpress", 21 | "launchBrowser": true, 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Resources/LanguageFiles/Display.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Mobile 7 | 8 | 9 | Web 10 | 11 | 12 | 13 | Full 14 | Narrow 15 | Wide 16 | 17 | 18 | Android vertical (480x800) 19 | iPad horizontal (1024x768) 20 | iPhone vertical (320x568) 21 | Standard (1366x768) 22 | 23 | 24 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Resources/LanguageFiles/EditorHints.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Button Text 8 | 9 | 10 | 11 | 12 | This block type does not have a renderer for this type of content area. 13 | 14 | 15 | 16 | 17 | The block '{0}' when displayed as {1} 18 | The block '{0}' cannot be displayed as {1} 19 | No renderer found for '{0}' 20 | 21 | 22 | Error while rendering {0} {1} 23 | 24 | 25 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Resources/LanguageFiles/GroupNames.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Default 7 | 8 | 9 | News 10 | 11 | 12 | Products 13 | 14 | 15 | SEO 16 | 17 | 18 | Site settings 19 | 20 | 21 | Specialized 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Resources/LanguageFiles/Views.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | E-mail 6 | No contact selected 7 | Phone 8 | 9 |
10 | The Company 11 | Customer Zone 12 | Log in 13 | Log out 14 | News & Events 15 | Products 16 |
17 | 18 | Search 19 | 20 | 21 | Latest news 22 | News list will be empty since no list root has been set 23 | 24 | 25 | EPiServer Search is not configured or is not active for this website. 26 | hits 27 | Search result 28 | resulted in 29 | Search 30 | Your search for 31 | no 32 | 33 |
34 |
-------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Resources/LanguageFiles/_ReadMe.txt: -------------------------------------------------------------------------------- 1 | All language files in this folder are included in the LocalizationService. 2 | 3 | The path to this folder is configured in EPiServerFramework.config: 4 | 5 | 6 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/ArticlePage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using AlloyTemplates 2 | @model PageViewModel 3 | 4 | @{ Layout = "~/Views/Shared/Layouts/_LeftNavigation.cshtml"; } 5 | 6 |

x.CurrentPage.PageName)>@Model.CurrentPage.PageName

7 |

x.CurrentPage.MetaDescription)>@Model.CurrentPage.MetaDescription

8 |
9 |
x.CurrentPage.MainBody)> 10 | @Html.DisplayFor(m => m.CurrentPage.MainBody) 11 |
12 |
13 | @Html.PropertyFor(x => x.CurrentPage.MainContentArea, new { CssClass = "row", Tag = Global.ContentAreaTags.TwoThirdsWidth }) 14 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/LandingPage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using AlloyTemplates 2 | @model PageViewModel 3 |
4 | @Html.PropertyFor(x => x.CurrentPage.MainContentArea, new { CssClass = "row equal-height", tag = Global.ContentAreaTags.FullWidth }) 5 |
6 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/NewsGeneratorPlugin/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using EPiServer.Framework.Web.Resources 2 | @using EPiServer.Shell.Navigation 3 | 4 | @{ Layout = null; } 5 | 6 | 7 | 8 | 9 | Content Security Policy Management 10 | 11 | 12 | @ClientResources.RenderResources("ShellCore") 13 | 14 | 15 | @ClientResources.RenderResources("ShellCoreLightTheme") 16 | 17 | 50 | 51 | 52 | @Html.CreatePlatformNavigationMenu() 53 |
54 |
55 |

Generate content

56 |
57 |
58 | 59 | 60 | 61 | 62 | 63 |
64 |
65 |
66 | 67 | 68 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/NewsPage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using AlloyTemplates 2 | @model PageViewModel 3 | 4 | @{ Layout = "~/Views/Shared/Layouts/_LeftNavigation.cshtml"; } 5 | 6 |

x.CurrentPage.PageName)>@Model.CurrentPage.PageName

7 |

x.CurrentPage.MetaDescription)>@Model.CurrentPage.MetaDescription

8 |
9 |
x.CurrentPage.MainBody)> 10 | @Html.DisplayFor(m => m.CurrentPage.MainBody) 11 |
12 |
13 | @Html.PropertyFor(x => x.CurrentPage.NewsList) 14 | @Html.PropertyFor(x => x.CurrentPage.MainContentArea, new { CssClass = "row", Tag = Global.ContentAreaTags.TwoThirdsWidth }) 15 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Preview/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model PreviewModel 2 | 3 | @foreach(var area in Model.Areas) 4 | { 5 | if(area.Supported) 6 | { 7 | @await Html.PartialAsync("TemplateHint", string.Format(System.Globalization.CultureInfo.CurrentUICulture, LocalizationService.Current.GetString("/preview/heading"), Model.PreviewContent.Name, LocalizationService.Current.GetString(area.AreaName))) 8 |
9 | @Html.DisplayFor(x => area.ContentArea, new {Tag = area.AreaTag}) 10 |
11 | } 12 | else 13 | { 14 | @await Html.PartialAsync("TemplateHint", string.Format(System.Globalization.CultureInfo.CurrentUICulture, LocalizationService.Current.GetString("/preview/norenderer"), Model.PreviewContent.Name, LocalizationService.Current.GetString(area.AreaName))) 15 | } 16 | } 17 | 18 | @if(!Model.Areas.Any()) 19 | { 20 | @await Html.PartialAsync("TemplateHint", string.Format(System.Globalization.CultureInfo.CurrentUICulture, LocalizationService.Current.GetString("/preview/norendereratall"), Model.PreviewContent.Name)) 21 | } 22 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/ProductPage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using AlloyTemplates 2 | @model PageViewModel 3 | 4 | @{ Layout = "~/Views/Shared/Layouts/_TwoPlusOne.cshtml"; } 5 | 6 |

x.CurrentPage.PageName)>@Model.CurrentPage.PageName

7 |

x.CurrentPage.MetaDescription)>@Model.CurrentPage.MetaDescription

8 |
9 |
x.CurrentPage.MainBody)> 10 | @Html.DisplayFor(m => m.CurrentPage.MainBody) 11 |
12 |
13 | @Html.PropertyFor(x => x.CurrentPage.MainContentArea, new { CssClass = "row", Tag = Global.ContentAreaTags.TwoThirdsWidth }) 14 | 15 | @section RelatedContent 16 | { 17 |
x.CurrentPage.PageImage)> 18 | 19 |
20 | 21 |
22 |

x.CurrentPage.PageName)>@Model.CurrentPage.PageName

23 |
24 | 25 | @Html.PropertyFor(x => x.CurrentPage.RelatedContentArea, new { CssClass = "row", Tag = Global.ContentAreaTags.OneThirdWidth }) 26 | } 27 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Register/Index.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | @using AlloyTemplates.Controllers 4 | @model AlloyTemplates.Models.RegisterViewModel 5 | @{ 6 | Layout = ""; 7 | } 8 | 9 | 10 | 11 | Create Administrator Account 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 |
20 | 21 |

Create Administrator Account

22 | 23 | @using (Html.BeginForm("", "Register", FormMethod.Post)) 24 | { 25 | @Html.AntiForgeryToken() 26 |
27 | @Html.LabelFor(m => m.Username) 28 | @Html.TextBoxFor(m => m.Username) 29 | @Html.ValidationMessageFor(m => m.Username) 30 |
31 |
32 | @Html.LabelFor(m => m.Email) 33 | @Html.TextBoxFor(m => m.Email) 34 | @Html.ValidationMessageFor(m => m.Email) 35 |
36 |
37 | @Html.LabelFor(m => m.Password) 38 | @Html.PasswordFor(m => m.Password) 39 | @Html.ValidationMessageFor(m => m.Password) 40 |
41 |
42 | @Html.LabelFor(m => m.ConfirmPassword) 43 | @Html.PasswordFor(m => m.ConfirmPassword) 44 | @Html.ValidationMessageFor(m => m.ConfirmPassword) 45 |
46 |
47 | @Html.ValidationMessage(RegisterController.ErrorKey) 48 |
49 |
50 | 51 |
52 | } 53 |
54 |
55 |
56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/SearchPage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using EPiServer.Editor 2 | @using EPiServer.Security 3 | @model SearchContentModel 4 | 5 | @{ 6 | Layout = "~/Views/Shared/Layouts/_TwoPlusOne.cshtml"; 7 | } 8 | 9 |
10 |
11 | @*We use GET to submit the form to enable bookmarking etc of search results. However, as GET will remove other 12 | query string values not in the form we can't use that in edit mode.*@ 13 | 14 | @{ 15 | using (Html.BeginForm(null, null, Html.ViewContext.IsInEditMode() ? FormMethod.Post : FormMethod.Get, new { @action = Model.Layout.SearchActionUrl })) 16 | { 17 | 18 | 19 | } 20 | } 21 |
22 |
23 | 24 | @if (Model.Hits != null) 25 | { 26 |
27 |
28 |

@Html.Translate("/searchpagetemplate/result")

29 |

30 | @Html.Translate("/searchpagetemplate/searchfor") @Model.SearchedQuery 31 | @Html.Translate("/searchpagetemplate/resultedin") 32 | @if (Model.NumberOfHits > 0) 33 | { 34 | @Model.NumberOfHits 35 | } 36 | else 37 | { 38 | @Html.Translate("/searchpagetemplate/zero") 39 | } 40 | @Html.Translate("/searchpagetemplate/hits") 41 |

42 |
43 |
44 | 45 |
46 |
47 | @foreach (var hit in Model.Hits) 48 | { 49 |
50 |

@hit.Title

51 |

@hit.Excerpt

52 |
53 |
54 | } 55 |
56 |
57 | 58 | } 59 | 60 | @if (Model.SearchServiceDisabled && Html.ViewContext.IsInEditMode()) 61 | { 62 | @await Html.PartialAsync("TemplateHint", Html.Translate("/searchpagetemplate/disabled").ToString()) 63 | } 64 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Blocks/ButtonBlock.cshtml: -------------------------------------------------------------------------------- 1 | @model ButtonBlock 2 | 3 | m.ButtonText)> 4 | @{ 5 | var buttonText = string.IsNullOrWhiteSpace(Model.ButtonText) 6 | ? LocalizationService.Current.GetString("/blocks/buttonblockcontrol/buttondefaulttext") 7 | : Model.ButtonText; 8 | } 9 | @buttonText 10 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Blocks/EditorialBlock.cshtml: -------------------------------------------------------------------------------- 1 | @model EditorialBlock 2 | 3 |
x.MainBody)> 4 | @Html.DisplayFor(x => Model.MainBody) 5 |
-------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Blocks/JumbotronBlockWide.cshtml: -------------------------------------------------------------------------------- 1 | @model JumbotronBlock 2 | 3 |
4 |
5 | @Html.PropertyFor(m=>m.Image) 6 |
7 | 8 |
9 |

m.Heading)>@Model.Heading

10 |

m.SubHeading)>@Model.SubHeading

11 | m.ButtonText)>@Model.ButtonText 12 |
13 |
-------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Blocks/NoRenderer.cshtml: -------------------------------------------------------------------------------- 1 | @await Html.PartialAsync("TemplateHint", Html.Translate("/blocks/norenderer/message").ToString()) 2 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Blocks/SiteLogotypeBlock.cshtml: -------------------------------------------------------------------------------- 1 | @model SiteLogotypeBlock 2 | 3 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Blocks/TeaserBlock.cshtml: -------------------------------------------------------------------------------- 1 | @using EPiServer.Core 2 | 3 | @model TeaserBlock 4 | 5 |
6 | @*Link the teaser block only if a link has been set and not displayed in preview*@ 7 | @using (Html.BeginConditionalLink 8 | (!ContentReference.IsNullOrEmpty(Model.Link) && !(Html.ViewContext.IsPreviewMode()), 9 | Url.PageLinkUrl(Model.Link), 10 | Model.Heading)) 11 | { 12 |

x.Heading)>@Model.Heading

13 |

x.Text)>@Model.Text

14 |
x.Image)>
15 | } 16 | 17 |
18 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Blocks/TeaserBlockWide.cshtml: -------------------------------------------------------------------------------- 1 | @model TeaserBlock 2 | 3 |
4 | @*Link the teaser block only if a link has been set and not displayed in preview*@ 5 | @using(Html.BeginConditionalLink( 6 | !ContentReference.IsNullOrEmpty(Model.Link) && !(Html.ViewContext.IsPreviewMode()), 7 | Url.PageLinkUrl(Model.Link), 8 | Model.Heading)) 9 | { 10 |
11 |
x.Image)> 12 | 13 |
14 |
15 |

x.Heading)>@Model.Heading

16 |

x.Text)>@Model.Text

17 |
18 |
19 | } 20 |
21 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Breadcrumbs.cshtml: -------------------------------------------------------------------------------- 1 | @using EPiServer.Core 2 | @using EPiServer.Web 3 | @*Helper used as template for a page in the bread crumb, recursively triggering the rendering of the next page*@ 4 | @{ 5 | HelperResult ItemTemplate(HtmlHelpers.MenuItem breadCrumbItem) 6 | { 7 | if (breadCrumbItem.Selected) 8 | { 9 | if (breadCrumbItem.Page.HasTemplate() && !breadCrumbItem.Page.ContentLink.CompareToIgnoreWorkID(Model.CurrentPage.ContentLink)) 10 | { 11 | @Html.PageLink(breadCrumbItem.Page) 12 | } 13 | else 14 | { 15 | @breadCrumbItem.Page.PageName 16 | } 17 | if (!breadCrumbItem.Page.ContentLink.CompareToIgnoreWorkID(Model.CurrentPage.ContentLink)) 18 | { 19 | / 20 | @Html.MenuList(breadCrumbItem.Page.ContentLink, ItemTemplate) 21 | } 22 | } 23 | return new HelperResult(w => Task.CompletedTask); 24 | } 25 | } 26 | 27 | 28 |
29 |
30 |
    31 | @Html.ContentLink(SiteDefinition.Current.StartPage) 32 | / 33 | @Html.MenuList(SiteDefinition.Current.StartPage, ItemTemplate, requireVisibleInMenu: false, requirePageTemplate: false) 34 |
35 |
36 |
-------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Components/ContactBlock/Default.cshtml: -------------------------------------------------------------------------------- 1 | @model ContactBlockModel 2 | 3 |
4 | @Html.PropertyFor(x => x.Image) 5 |

x.Heading)>@Model.Heading

6 | @Html.PropertyFor(x => x.ContactPage) 7 | @if(Model.ShowLink) 8 | { 9 | x.LinkText)> 10 | @Model.LinkText 11 | 12 | } 13 |
-------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Components/ImageFile/Default.cshtml: -------------------------------------------------------------------------------- 1 | @model ImageViewModel 2 | 3 | @Model.Name 4 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Components/PageListBlock/Default.cshtml: -------------------------------------------------------------------------------- 1 | @model PageListModel 2 | @Html.FullRefreshPropertiesMetaData(new[] { "IncludePublishDate", "IncludeIntroduction", "Count", "SortOrder", "Root", "PageTypeFilter", "CategoryFilter", "Recursive" }) 3 |

x.Heading)>@Model.Heading

4 |
5 | 6 | @foreach(var page in Model.Pages) 7 | { 8 |
9 |

10 | @Html.PageLink(page) 11 |

12 | @if(Model.ShowPublishDate && page.StartPublish.HasValue) 13 | { 14 |

@Html.DisplayFor(x => page.StartPublish)

15 | } 16 | @if(Model.ShowIntroduction && page is SitePageData) 17 | { 18 | var withTeaserText = (SitePageData) page; 19 |

@withTeaserText.TeaserText

20 | } 21 |
22 |
23 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Components/VideoFile/Default.cshtml: -------------------------------------------------------------------------------- 1 | @using EPiServer.Framework.Web.Resources 2 | @model VideoViewModel 3 | @{ 4 | ClientResources.RequireScript(Href("~/jwplayer/jwplayer.js")); 5 | 6 | //The video element's ID needs to be unique in order for several video blocks and possible the same video block, to work on the same page 7 | var containerId = "video-container-" + Guid.NewGuid().GetHashCode(); 8 | } 9 | @Html.FullRefreshPropertiesMetaData(new []{"Url"}) 10 |
m.Url)> 11 |
12 |
13 |
14 | 15 | 30 |
31 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/DisplayTemplates/ContactPage.cshtml: -------------------------------------------------------------------------------- 1 | @model ContactPage 2 | 3 |

4 | @if(Model != null) 5 | { 6 | @Model.PageName
7 | @Html.Translate("/contact/phone")@: : @Model.Phone
8 | @Html.Translate("/contact/email")@: : @Html.DisplayFor(m => m.Email) 9 | } 10 | else 11 | { 12 | @Html.Translate("/contact/noneselected") 13 | } 14 |

-------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/DisplayTemplates/DateTime.cshtml: -------------------------------------------------------------------------------- 1 | @model DateTime 2 | @Model.ToString("d MMMM yyyy") 3 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/DisplayTemplates/Image.cshtml: -------------------------------------------------------------------------------- 1 | @model EPiServer.Core.ContentReference 2 | @if (Model != null) 3 | { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/DisplayTemplates/StringsCollection.cshtml: -------------------------------------------------------------------------------- 1 | @model IEnumerable 2 | @if(Model != null && Model.Any()) 3 | { 4 |
    5 | @foreach(var stringValue in Model) 6 | { 7 |
  • @stringValue
  • 8 | } 9 |
10 | } 11 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/DisplayTemplates/_ReadMe.txt: -------------------------------------------------------------------------------- 1 | The views in this folder are used when rendering properties using Html.DisplayFor and Html.PropertyFor. 2 | Display templates are selected based on the type name of the property and, optionally, by UIHint and DataType attributes added to the property. 3 | Note that the CMS adds a number of view templates which do not exist in this folder but found through a view engine which the CMS adds at start up. 4 | Those view templates can be found in \Application\Util\Views\Shared\DisplayTemplates. Views in this folder takes precedence meaning 5 | that we can override those templates, which is currently done for content areas. -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Footer.cshtml: -------------------------------------------------------------------------------- 1 | @model IPageViewModel 2 |
3 | 40 |
41 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Header.cshtml: -------------------------------------------------------------------------------- 1 | @using EPiServer.Editor 2 | @using EPiServer.Core 3 | @using EPiServer.Web 4 | @model IPageViewModel 5 |
6 | 51 |
52 | 53 |
-------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Layouts/_LeftNavigation.cshtml: -------------------------------------------------------------------------------- 1 | @model IPageViewModel 2 | 3 | @{ Layout = "~/Views/Shared/Layouts/_Root.cshtml"; } 4 | 5 | @{await Html.RenderPartialAsync("Breadcrumbs", Model);} 6 | 7 |
8 |
9 |
10 |
11 | @{await Html.RenderPartialAsync("SubNavigation", Model);} 12 | @RenderSection("RelatedContent", false) 13 |
14 |
15 |
16 | 17 |
18 | @RenderBody() 19 |
20 |
21 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Layouts/_Root.cshtml: -------------------------------------------------------------------------------- 1 | 2 | @using EPiServer.Framework.Web.Mvc.Html 3 | @using AlloyTemplates.Business 4 | @model IPageViewModel 5 | 6 | 7 | 8 | 9 | 10 | 11 | @Model.CurrentPage.MetaTitle 12 | @if (Model.CurrentPage.MetaKeywords != null && Model.CurrentPage.MetaKeywords.Count > 0) 13 | { 14 | 15 | } 16 | @if (!string.IsNullOrWhiteSpace(Model.CurrentPage.MetaDescription)) 17 | { 18 | 19 | } 20 | 21 | @Html.CanonicalLink() 22 | @Html.AlternateLinks() 23 | 24 | @Html.RequiredClientResources("Header") @*Enable components to require resources. For an example, see the view for VideoBlock.*@ 25 | 26 | 27 | 28 | @if (Model.Layout.IsInReadonlyMode) 29 | { 30 | await Html.RenderPartialAsync("Readonly", Model); 31 | } 32 | 33 | @await Html.RenderEPiServerQuickNavigatorAsync() 34 | @Html.FullRefreshPropertiesMetaData() 35 |
36 | @if(!Model.Layout.HideHeader) 37 | { 38 | await Html.RenderPartialAsync("Header", Model); 39 | } 40 | @RenderBody() 41 | @if(!Model.Layout.HideFooter) 42 | { 43 | await Html.RenderPartialAsync("Footer", Model); 44 | } 45 |
46 | @Html.RequiredClientResources("Footer") 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Layouts/_TwoPlusOne.cshtml: -------------------------------------------------------------------------------- 1 | @using AlloyTemplates 2 | @model IPageViewModel 3 | @{ Layout = "~/Views/Shared/Layouts/_Root.cshtml"; } 4 | 5 | @{await Html.RenderPartialAsync("Breadcrumbs");} 6 | 7 |
8 | 9 |
10 | @RenderBody() 11 |
12 | 13 |
14 | @if (IsSectionDefined("RelatedContent")) 15 | { 16 | @RenderSection("RelatedContent") 17 | } 18 | else if (Model.CurrentPage is IHasRelatedContent) 19 | { 20 | @Html.PropertyFor(x => ((IHasRelatedContent)x.CurrentPage).RelatedContentArea, new { CssClass = "row", Tag = Global.ContentAreaTags.OneThirdWidth }) 21 | } 22 |
23 |
24 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/PagePartials/ContactPage.cshtml: -------------------------------------------------------------------------------- 1 | @model ContactPage 2 | 3 |
4 | 5 |

@Model.PageName

6 |

@Model.TeaserText

7 |

8 | @Html.Translate("/contact/email"): @Html.DisplayFor(x => x.Email)
9 | @Html.Translate("/contact/phone"): @Model.Phone 10 |

11 |
-------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/PagePartials/ContactPageWide.cshtml: -------------------------------------------------------------------------------- 1 | @model ContactPage 2 |
3 |
4 |
5 | 6 |
7 |

@Model.PageName

8 |

@Model.TeaserText

9 |

10 | @Html.Translate("/contact/email"): @Html.DisplayFor(x => x.Email)
11 | @Html.Translate("/contact/phone"): @Model.Phone 12 |

13 |
14 |
-------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/PagePartials/Page.cshtml: -------------------------------------------------------------------------------- 1 | @using EPiServer.Core 2 | @model SitePageData 3 | 4 |
5 | @using(Html.BeginConditionalLink(Model.HasTemplate(), Url.PageLinkUrl(Model), Model.PageName)) 6 | { 7 |

@Model.PageName

8 |

@Model.TeaserText

9 | @Html.DisplayFor(m => m.PageImage) 10 | } 11 |
-------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/PagePartials/PageWide.cshtml: -------------------------------------------------------------------------------- 1 | @using EPiServer.Core 2 | @model SitePageData 3 |
4 | @using(Html.BeginConditionalLink(Model.HasTemplate(), Url.PageLinkUrl(Model), Model.PageName)) 5 | { 6 |
7 |
8 | @Html.DisplayFor(m => m.PageImage) 9 |
10 |

@Model.PageName

11 |

@Model.TeaserText

12 |
13 | } 14 |
-------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/Readonly.cshtml: -------------------------------------------------------------------------------- 1 | @model IPageViewModel 2 | 3 |
-------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/SubNavigation.cshtml: -------------------------------------------------------------------------------- 1 | @model IPageViewModel 2 | 3 | @{ 4 | HelperResult SubLevelItemTemplate(HtmlHelpers.MenuItem subLevelItem) 5 | { 6 |
  • 7 | @Html.PageLink(subLevelItem.Page) 8 |
  • 9 | return new HelperResult(w => Task.CompletedTask); 10 | } 11 | } 12 | 13 | @{ 14 | HelperResult ItemTemplate(HtmlHelpers.MenuItem firstLevelItem) 15 | { 16 | 22 |
    23 |
      24 | @Html.MenuList(firstLevelItem.Page.ContentLink, SubLevelItemTemplate) 25 |
    26 |
    27 | return new HelperResult(w => Task.CompletedTask); 28 | } 29 | } 30 | 31 |
    32 |
    33 | @if (Model.Section != null) 34 | { 35 | @Html.MenuList(Model.Section.ContentLink, ItemTemplate) 36 | } 37 |
    38 |
    -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/TemplateError.cshtml: -------------------------------------------------------------------------------- 1 | @model ContentRenderingErrorModel 2 |
    3 |

    @string.Format(System.Globalization.CultureInfo.CurrentUICulture, LocalizationService.Current.GetString("/renderingerror/heading"), Model.ContentTypeName, Model.ContentName)

    4 |

    5 | @Model.Exception.Message
    6 | @Model.Exception.StackTrace 7 |

    8 |
    9 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Shared/TemplateHint.cshtml: -------------------------------------------------------------------------------- 1 | @model string 2 |

    @Model

    3 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/StandardPage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using AlloyTemplates 2 | @model PageViewModel 3 | 4 | @{ Layout = "~/Views/Shared/Layouts/_LeftNavigation.cshtml"; } 5 | 6 |

    x.CurrentPage.PageName)>@Model.CurrentPage.PageName

    7 |

    x.CurrentPage.MetaDescription)>@Model.CurrentPage.MetaDescription

    8 |
    9 |
    x.CurrentPage.MainBody)> 10 | @Html.DisplayFor(m => m.CurrentPage.MainBody) 11 |
    12 |
    13 | @Html.PropertyFor(x => x.CurrentPage.MainContentArea, new { CssClass = "row", Tag = Global.ContentAreaTags.TwoThirdsWidth }) 14 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/StartPage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using AlloyTemplates 2 | @model PageViewModel 3 | 4 | @Html.PropertyFor(x => x.CurrentPage.MainContentArea, new { CssClass = "row equal-height", tag = Global.ContentAreaTags.FullWidth }) 5 | @Html.PropertyFor(x => x.CurrentPage.AllowCertainBlockTypes, new { CssClass = "row equal-height", tag = Global.ContentAreaTags.HalfWidth }) 6 | @Html.PropertyFor(x => x.CurrentPage.RestrictCertainBlockTypes, new { CssClass = "row equal-height", tag = Global.ContentAreaTags.HalfWidth }) 7 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
    7 |
    8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 36 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/_ReadMe.txt: -------------------------------------------------------------------------------- 1 | View locations in Alloy follows a number of conventions in addition to the default ASP.NET MVC conventions: 2 | * Views for pages and blocks with their own controllers use standard ASP.NET MVC conventions - /.cshtml 3 | * Page types which don't have their own controller are mapped to /Index.cshtml by DefaultPageController 4 | * Views for block types which don't have their own controllers are found in Shared/Blocks 5 | * Partial views for page types which don't have their own controllers for partial requests are found in Shared/PagePartials -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using EPiServer.Framework.Localization 2 | @using EPiServer.Web.Mvc.Html 3 | @using EPiServer.Shell.Web.Mvc.Html 4 | @using EPiServer.Core 5 | @using EPiServer.Web 6 | @using EPiServer.Web.Mvc 7 | @using EPiServer.Web.Routing 8 | @using AlloyTemplates.Helpers 9 | @using EPiServer.Templates.Alloy.Mvc 10 | @using AlloyTemplates.Models.Blocks 11 | @using AlloyTemplates.Models.Media 12 | @using AlloyTemplates.Models.Pages 13 | @using AlloyTemplates.Models.ViewModels 14 | @using Microsoft.AspNetCore.Mvc.Razor 15 | @using Microsoft.AspNetCore.Html 16 | 17 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 18 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/Views/_viewstart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/Layouts/_Root.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "EPiServer": "Information", 7 | "Microsoft.Hosting.Lifetime": "Information" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "EPiServer": "Warning", 7 | "Microsoft.Hosting.Lifetime": "Information" 8 | } 9 | }, 10 | "urls": "http://*:8000/;", 11 | "AllowedHosts": "*", 12 | "EPiServer": { 13 | "CmsUI": { 14 | "Upload": { 15 | "FileSizeLimit": 10485760 16 | }, 17 | "SelectionFactories": { 18 | "Test": { 19 | "Selection1": "Value1", 20 | "Selection2": "Value2" 21 | } 22 | } 23 | }, 24 | "Find": { 25 | "ServiceUrl": "https://demo01.find.episerver.net/2P6GwtX0FeHN8ce4TNl3CCUtPNzPmoKA/", 26 | "DefaultIndex": "manhhung.nguyen_manhhungindex1" 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/bundleconfig.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "outputFileName": "wwwroot/css/css.min.css", 4 | "inputFiles": [ 5 | "wwwroot/css/bootstrap.css", 6 | "wwwroot/css/bootstrap-responsive.css", 7 | "wwwroot/css/media.css", 8 | "wwwroot/css/style.css", 9 | "wwwroot/css/editmode.css" 10 | ] 11 | }, 12 | { 13 | "outputFileName": "wwwroot/js/script.min.js", 14 | "inputFiles": [ 15 | "wwwroot/js/jquery.js", 16 | "wwwroot/js/bootstrap.js" 17 | ], 18 | "minify": { 19 | "enabled": true, 20 | "renameLocals": true 21 | }, 22 | "sourceMap": false 23 | } 24 | ] -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | sql: 4 | build: 5 | dockerfile: ./docker/Sql.Dockerfile 6 | context: . 7 | # comment out below lines if you want to expose sql server port for using with other tool like sql server managemnent studio 8 | # ports: 9 | # - "1433:1433" 10 | environment: 11 | SA_PASSWORD: ${sa_password} 12 | ACCEPT_EULA: "Y" 13 | DATABASE_NAME: ${database_name} 14 | image: alloy/db:${sql_tag} 15 | web: 16 | build: 17 | dockerfile: ./docker/Web.Dockerfile 18 | context: . 19 | ports: 20 | - "${site_port}:8000" 21 | environment: 22 | ConnectionStrings__EPiServerDB: "Server=sql;Database=${database_name};User Id=sa;Password=${sa_password};MultipleActiveResultSets=True;" 23 | depends_on: 24 | - sql 25 | image: alloy/web:${web_tag} 26 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/docker/Sql.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/mssql/server:2019-latest AS base 2 | 3 | USER root 4 | 5 | ENV ACCEPT_EULA=Y 6 | ENV MSSQL_TCP_PORT=1433 7 | EXPOSE 1433 8 | 9 | WORKDIR /src 10 | COPY ./docker/build-script/attach_db.sh /docker/attach_db.sh 11 | COPY ./App_Data/Alloy.mdf /docker/Alloy.mdf 12 | 13 | RUN chmod -R 777 /docker/. 14 | 15 | ENTRYPOINT /docker/attach_db.sh & /opt/mssql/bin/sqlservr 16 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/docker/Web.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim AS base 2 | WORKDIR /app 3 | EXPOSE 8000 4 | 5 | FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim AS build 6 | WORKDIR /src 7 | COPY . . 8 | RUN dotnet restore "AlloyMvcTemplates.csproj" 9 | 10 | RUN dotnet build "AlloyMvcTemplates.csproj" -c Release -o /app/build 11 | 12 | FROM build AS publish 13 | RUN dotnet publish "AlloyMvcTemplates.csproj" -c Release -o /app/publish 14 | COPY ./docker/build-script/wait_sqlserver_start_and_attachdb.sh /app/publish/wait_sqlserver_start_and_attachdb.sh 15 | COPY ./App_Data/DefaultSiteContent.episerverdata /app/publish/App_Data/DefaultSiteContent.episerverdata 16 | 17 | FROM base AS final 18 | WORKDIR /app 19 | COPY --from=publish /app/publish . 20 | #wait sql server container start and attach alloy database then start web 21 | ENTRYPOINT ./wait_sqlserver_start_and_attachdb.sh 22 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/docker/build-script/attach_db.sh: -------------------------------------------------------------------------------- 1 | sleep 30s 2 | /opt/mssql-tools/bin/sqlcmd -S . -U sa -P ${SA_PASSWORD} \ 3 | -Q "CREATE DATABASE [${DATABASE_NAME}] ON (FILENAME ='/docker/Alloy.mdf') FOR ATTACH" -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/docker/build-script/wait_sqlserver_start_and_attachdb.sh: -------------------------------------------------------------------------------- 1 | 2 | sleep 120s 3 | echo "Connection string:" $ConnectionStrings__EPiServerDB 4 | echo "Site port:" $site_port 5 | dotnet AlloyMvcTemplates.dll -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/docker/run-script/build.sh: -------------------------------------------------------------------------------- 1 | docker load -i alloy-db.tar 2 | docker load -i alloy-web.tar -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/docker/run-script/build_web_only.sh: -------------------------------------------------------------------------------- 1 | docker load -i alloy-web.tar -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/docker/run-script/run.sh: -------------------------------------------------------------------------------- 1 | docker-compose -f docker-compose.yml up -d -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/docker/run-script/stop.sh: -------------------------------------------------------------------------------- 1 | docker-compose -f docker-compose.yml down -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/docker/run-script/stop_web_only.sh: -------------------------------------------------------------------------------- 1 | docker-compose rm -f -s -v web -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/favicon.ico -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/module.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/modulesbin/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/modulesbin/.gitkeep -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/ClientResources/Images/icons/layoutIcons24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/ClientResources/Images/icons/layoutIcons24x24.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/ClientResources/Styles/LayoutIcons.css: -------------------------------------------------------------------------------- 1 | .Sleek .epi-icon__layout--full { 2 | background: url('../Images/icons/layoutIcons24x24.png') 0px -24px no-repeat; 3 | height: 24px; 4 | width: 24px; 5 | } 6 | .Sleek .epi-icon__layout--half { 7 | background: url('../Images/icons/layoutIcons24x24.png') 0px -48px no-repeat; 8 | height: 24px; 9 | width: 24px; 10 | } 11 | .Sleek .epi-icon__layout--two-thirds { 12 | background: url('../Images/icons/layoutIcons24x24.png') 0px -72px no-repeat; 13 | height: 24px; 14 | width: 24px; 15 | } 16 | .Sleek .epi-icon__layout--one-third { 17 | background: url('../Images/icons/layoutIcons24x24.png') 0px -96px no-repeat; 18 | height: 24px; 19 | width: 24px; 20 | } 21 | .Sleek .epi-icon__layout--one-quarter { 22 | background: url('../Images/icons/layoutIcons24x24.png') 0px -120px no-repeat; 23 | height: 24px; 24 | width: 24px; 25 | } 26 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/ClientResources/Styles/Styles.css: -------------------------------------------------------------------------------- 1 | @import url("LayoutIcons.css"); 2 | 3 | .epiStringList .dijitTextArea { 4 | width: 250px; 5 | } 6 | 7 | .epiStringList .epiStringListError .dijitTextArea { 8 | border: solid 1px #d46464; 9 | } 10 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/css/editmode.css: -------------------------------------------------------------------------------- 1 | /* CSS specific to edit mode, such as help content displayed to the editor */ 2 | 3 | .alert-info { 4 | border-color: #B8C0C5; 5 | color: black; 6 | font-family: 'Inter'; 7 | font-size: 1em; 8 | font-style: italic; 9 | background-color: #B8C0C5; 10 | box-shadow: 3px 3px 5px #CCC; 11 | text-align: center; 12 | } 13 | 14 | .alert-error p { 15 | text-align: left; 16 | } 17 | 18 | .alert-error .heading { 19 | font-weight: bold; 20 | color: #ff0000; 21 | } 22 | 23 | .alert-error .details { 24 | font-size: 0.8em; 25 | max-height: 100px; 26 | overflow: scroll; 27 | } 28 | 29 | .header.dim { 30 | margin: 2% 0; 31 | opacity: 0.3; 32 | } 33 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/css/editor.css: -------------------------------------------------------------------------------- 1 | /* Styles used by the TinyMCE editor */ 2 | 3 | h2 {EditMenuName:Header 2;} 4 | h3 {EditMenuName:Header 3;} 5 | 6 | /*Block Preview*/ 7 | .alert-info { 8 | background-color: #FFF8AA; 9 | border-color: #858585; 10 | color: #000000; 11 | font-family: Verdana; 12 | font-size: 12px; 13 | } 14 | 15 | .header.dim { 16 | margin: 2% 0; 17 | opacity: 0.3; 18 | } -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/css/media.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | /* CSS Document */ 3 | 4 | 5 | 6 | @media (max-width: 979px) { 7 | .span12, .span8, .span6, .span4 { 8 | float: none; 9 | width: auto !important; 10 | } 11 | 12 | .span4 h2, .span6 h2 13 | { 14 | clear:both; 15 | } 16 | 17 | .teaserblock.full h2, .teaserblock.wide h2 { 18 | font-size: 2.5em; 19 | } 20 | 21 | .subHeader 22 | { 23 | width:100% !important; 24 | font-weight:normal !important; 25 | } 26 | 27 | .jumbotronblock .span4 28 | { 29 | display:none; 30 | } 31 | 32 | .media .mediaImg img 33 | { 34 | width:75%;} 35 | 36 | 37 | .hideMyTracks {display:none;} 38 | 39 | } 40 | 41 | 42 | 43 | @media (max-width: 834px) { 44 | 45 | .teaserblock.full h2, .teaserblock.wide h2 { 46 | clear:both; 47 | } 48 | 49 | .teaserblock.full h2, .teaserblock.wide h2, .teaserblock.full p, .teaserblock.wide p { 50 | text-align:center; 51 | } 52 | 53 | .teaserblock.full img, .teaserblock.wide img { 54 | width:75%; 55 | } 56 | 57 | #header .span2 58 | { 59 | float:left; 60 | width:20% !important; 61 | } 62 | 63 | #header .span10 64 | { 65 | float:right; 66 | } 67 | 68 | .span12 .media .mediaText, .span8 .media .mediaText 69 | { 70 | clear:both; 71 | margin:0 2% 5px; 72 | } 73 | 74 | } 75 | 76 | @media (max-width: 767px) { 77 | 78 | h1 79 | { 80 | font-size:35px !important; 81 | } 82 | 83 | h2 84 | { 85 | font-size:20px !important; 86 | } 87 | 88 | .introduction { 89 | font-size:1.2em !important; 90 | margin:2% 0 4% 0; 91 | } 92 | 93 | .alloyMenu .navbar .nav>li>a { 94 | color:#323335; 95 | padding-bottom:12px; 96 | line-height:23px; 97 | text-shadow:none !important; 98 | outline:none; 99 | } 100 | 101 | .alloyMenu .navbar .nav>li>ul>li a:hover { 102 | outline:1px solid; 103 | background:#2980bd; 104 | } 105 | 106 | 107 | .span3 { 108 | width:100% !important; 109 | 110 | } 111 | 112 | .teaserblock img { 113 | width:75%; 114 | } 115 | 116 | .btn-blue { 117 | margin-right:1%; 118 | float:left; 119 | clear:none; 120 | } 121 | 122 | .searchButton { 123 | float:right; 124 | margin-top:7px !important; 125 | } 126 | 127 | .alloyMenu .navbar-search .search-query 128 | { 129 | max-width:70%; 130 | } 131 | 132 | 133 | #header .span2 134 | { 135 | float:left; 136 | width:20% !important; 137 | } 138 | 139 | #header .span10 140 | { 141 | float:right; 142 | } 143 | 144 | } 145 | 146 | -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/New_FDT_Press_Contact_.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/New_FDT_Press_Contact_.JPG -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/carouselbackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/carouselbackground.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/contact.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/contact.jpg -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/exampelspan4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/exampelspan4.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/experts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/experts.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/fallows-media-wide.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/fallows-media-wide.jpg -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/leader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/leader.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/leader2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/leader2.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/logotype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/logotype.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/meet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/meet.jpg -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/page-type-thumbnail-article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/page-type-thumbnail-article.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/page-type-thumbnail-contact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/page-type-thumbnail-contact.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/page-type-thumbnail-product.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/page-type-thumbnail-product.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/page-type-thumbnail-standard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/page-type-thumbnail-standard.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/page-type-thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/page-type-thumbnail.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/person.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/person.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/plan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/plan.jpg -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/play.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/playInactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/playInactive.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/productLandingv2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/productLandingv2.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/searchbutton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/searchbutton.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/searchbuttonsmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/searchbuttonsmall.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/gfx/track.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/gfx/track.jpg -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/img/favicon.ico -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/jwplayer/player.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/jwplayer/player.swf -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/jwplayer/preview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/jwplayer/preview.jpg -------------------------------------------------------------------------------- /sample/AlloyMvcTemplates/wwwroot/jwplayer/video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/PowerSlice/294af61f339040d267f33fc7ac4800064efd229d/sample/AlloyMvcTemplates/wwwroot/jwplayer/video.mp4 --------------------------------------------------------------------------------