├── .gitattributes ├── .gitignore ├── AlloyReact ├── .babelrc ├── AlloyReact.csproj ├── AlloyReact.sln ├── App_Data │ ├── DefaultSiteContent.episerverdata │ ├── EPiServerDB_f19fa128.mdf │ ├── EPiServerDB_f19fa128_log.ldf │ └── blobs │ │ ├── 0053dd8be47647c09b6d592fddbc90aa │ │ ├── 5af56c1426724c0ca388e9c2ea6399d0.jpg │ │ └── 5af56c1426724c0ca388e9c2ea6399d0_Thumbnail.jpg │ │ ├── 0488427b3c1843eb9671420355f89898 │ │ └── 0a3b3bfc98c644458cf557c98a999c1a.jpg │ │ ├── 05925076ec86458288064a99275b99e8 │ │ └── 723817a183ac4ada82e87421f1bf4033.png │ │ ├── 18e4d63a23de42da9f75c284b22e2118 │ │ └── ecc95455fbcf46dfb11d8a8515dacf79.jpg │ │ ├── 322815899a3242c0998c56ab05cf3853 │ │ └── 4e473727445d48b983ee4b7dd5900e83.png │ │ ├── 43e0b8aca4d54992aae25cbf27feba90 │ │ └── 4f5f01fe279d4e468b5ac5334b34134f.png │ │ ├── 4416f63d6acd41a7bf4c37aae578c6e2 │ │ └── 649294cc796f41929a1965718dffd37a.png │ │ ├── 45db4053ee324a4dbfa198de8a0b0d66 │ │ └── e5b75ca76f414e5a8a7b7ca19ee41841.png │ │ ├── 4e6dc9529d6343abb1670badfe7077ac │ │ └── 0b29c9305eda43dd83e3981a6ed3a82d.png │ │ ├── 514777e7c22f4e0ebe7303e5f6a11356 │ │ └── f08006eb5ef94dcb812559722f8de4d0.jpg │ │ ├── 54f7f338fed549eab15a80844c15e3cd │ │ └── 7dc53b1842e240979311291983a7ae66.png │ │ ├── 5e7cb947aebd451a8a9bab416d608434 │ │ └── 7e0637ed94d34711a656619e53f487e8.png │ │ ├── 6711854292214695945bae2537a8003f │ │ └── 4e5447acdec14f9d9e64357b785304fd.png │ │ ├── 738a64528f814c328ece038175fb75c7 │ │ ├── 75b9ce805d054490bca033587498917a.png │ │ └── 75b9ce805d054490bca033587498917a_Thumbnail.png │ │ ├── 83fd8d0600544baa8e1da5c8b075d9bc │ │ ├── 1a8e1607451f46508bc92399484aac6b.png │ │ └── 1a8e1607451f46508bc92399484aac6b_Thumbnail.png │ │ ├── 8fc23add042144f2a9d2db6e7b2a5b91 │ │ └── eb53bd3a3bd442d98db93e8d2c3fc1af.png │ │ ├── 9102db1c75a541a89154088b78c6d4e2 │ │ └── 14a448bd83c44587807a4aab90d730b1.png │ │ ├── 95f247ea78b642338a2d796cbbc79f13 │ │ └── 1d2e8fda4a944335b2f2fd05c1c0eec7.png │ │ ├── 9aa23ec0b8c24c0db7b8627c9698a72b │ │ └── 36444e66f2354570b131138f502e14d4.png │ │ ├── 9d89c035535043de923324c3796a90b7 │ │ ├── 78e08f306fc44c03888da8bab14fee3e.png │ │ └── 78e08f306fc44c03888da8bab14fee3e_Thumbnail.png │ │ ├── a2b00021b65c4d3c8ba671edd4074200 │ │ └── 642752e9ab914dbc8bfbff7b158c1a0b.jpg │ │ ├── aa3bd220449d40aea77ca5daa38ad91a │ │ └── c101fa5b5d844132bd6e0662c89fdd91.png │ │ ├── b52964b56069455e8b586e9627aba799 │ │ └── 2aedf124d98949208342b1ec395f07c3.png │ │ ├── b52e5a0b7b6c40ce8800b73847e4dc7e │ │ ├── 3654f95ce9c243b88a097eafa064ebda.png │ │ └── 3654f95ce9c243b88a097eafa064ebda_Thumbnail.png │ │ ├── b6f6dfeb26e64ae68f8b1ac352d7435b │ │ └── 17183bbd93a049bb9911f4baeebeff3e.png │ │ ├── b943d791c016463782568a7c45dfcb33 │ │ └── 7dba176dd85e4d898462b6f11111b163.png │ │ ├── bcb01052992e48c49313074e2512c2b9 │ │ └── 4744fa764ccc4f51876166ac614abe10.png │ │ ├── cacab32eabb6426eb2af20df4878ea59 │ │ └── 26d4468ea1a24ddcb287b129546bc9bb.png │ │ ├── d261560357dd4573b4c50cc3186ef899 │ │ └── 364d4d07c3fa4f8db401ce9504688eec.png │ │ ├── d655dc5e721049e6813701cf22047a77 │ │ └── ad15c26de9ae4961bb2684c9fc0e3a22.jpg │ │ ├── ddb8ace5bd584ad2aa5b7cce1a6b9869 │ │ ├── 6598d114649f403494a5e39ae0e52e12.png │ │ └── 6598d114649f403494a5e39ae0e52e12_Thumbnail.png │ │ ├── de77c68c0020437e881872e0809ae65b │ │ └── e6b6a9b869714ea485f3fd17c38b537f.png │ │ ├── e88a2e230b1f473c8ffe59f5de341aea │ │ └── 73bc58da26334206b2fee86b6f7c0a65.png │ │ ├── f0083115f1f34da28ec301d4e0fa201e │ │ └── 92c46e048fef43d6978fb9afed9f5aaa.jpg │ │ ├── f687a3341cde4af696c7f7d3248b870b │ │ └── 415137265cd848ce8736d489f047c8c3.png │ │ ├── f879cb724a5e4e9c980f3ce69ed37f35 │ │ └── ccdc110de0d64864b73fcb36c1b77a53.png │ │ ├── f8f3db6dd82d4084abb126b9cc371a8f │ │ └── 8fbb14eb5b8948fd80cbe9b6484ad482.mp4 │ │ ├── f93a55b27d5642d0b4645335fdbad552 │ │ └── bd34e19f5c0f4a2ba1c1c8d5f01808ae.png │ │ ├── faa6473aae9d4171ae0ecfe72b308129 │ │ └── 9b4566cb57114c5d82f8b011b3317164.png │ │ ├── fcb0ec7c0e1e45cba14e955d27c02eae │ │ └── 0e06c4e11a794b428ab4f881663b88e8.png │ │ └── fea10ef30cbd4548b2d80a2b895b6922 │ │ └── 930770cbd8c9437da02cb1c0468945c2.jpg ├── Business │ ├── AdministratorRegistrationPage.cs │ ├── Channels │ │ ├── DisplayResolutionBase.cs │ │ ├── DisplayResolutions.cs │ │ ├── MobileChannel.cs │ │ └── WebChannel.cs │ ├── ContentExtensions.cs │ ├── ContentLocator.cs │ ├── EditorDescriptors │ │ ├── ContactPageSelectionFactory.cs │ │ ├── ContactPageSelector.cs │ │ └── StringListEditorDescriptor.cs │ ├── IModifyLayout.cs │ ├── Initialization │ │ ├── BundleConfig.cs │ │ ├── CustomizedRenderingInitialization.cs │ │ ├── DependencyResolverInitialization.cs │ │ ├── DisplayModesInitialization.cs │ │ ├── DisplayRegistryInitialization.cs │ │ └── FilterConfig.cs │ ├── PageContextActionFilter.cs │ ├── PageTypeExtensions.cs │ ├── PageViewContextFactory.cs │ ├── Rendering │ │ ├── AlloyContentAreaRenderer.cs │ │ ├── ErrorHandlingContentRenderer.cs │ │ ├── IContainerPage.cs │ │ ├── ICustomCssInContentArea.cs │ │ ├── SiteViewEngine.cs │ │ └── TemplateCoordinator.cs │ ├── SearchService.cs │ ├── ServiceLocatorDependencyResolver.cs │ └── UIDescriptors │ │ └── ContainerPageUIDescriptor.cs ├── ClientResources │ ├── Images │ │ └── icons │ │ │ └── layoutIcons24x24.png │ ├── Scripts │ │ └── Editors │ │ │ └── StringList.js │ └── Styles │ │ ├── LayoutIcons.css │ │ └── Styles.css ├── Controllers │ ├── ContactBlockController.cs │ ├── DefaultPageController.cs │ ├── ImageFileController.cs │ ├── PageControllerBase.cs │ ├── PageListBlockController.cs │ ├── PreviewController.cs │ ├── RegisterController.cs │ ├── SearchPageController.cs │ ├── StartPageController.cs │ └── VideoFileController.cs ├── EPiServerLog.config ├── Global.asax ├── Global.asax.cs ├── Global.cs ├── Helpers │ ├── CategorizableExtensions.cs │ ├── HtmlHelpers.cs │ └── UrlHelpers.cs ├── Models │ ├── Blocks │ │ ├── ButtonBlock.cs │ │ ├── ContactBlock.cs │ │ ├── EditorialBlock.cs │ │ ├── FormBlock.cs │ │ ├── JumbotronBlock.cs │ │ ├── PageListBlock.cs │ │ ├── SiteBlockData.cs │ │ ├── SiteLogotypeBlock.cs │ │ ├── TeaserBlock.cs │ │ └── ThreeKeyFactsBlock.cs │ ├── Media │ │ ├── GenericMedia.cs │ │ ├── ImageFile.cs │ │ └── VideoFile.cs │ ├── Pages │ │ ├── ArticlePage.cs │ │ ├── ContactPage.cs │ │ ├── ContainerPage.cs │ │ ├── IHasRelatedContent.cs │ │ ├── ISearchPage.cs │ │ ├── LandingPage.cs │ │ ├── NewsPage.cs │ │ ├── ProductPage.cs │ │ ├── SearchPage.cs │ │ ├── SitePageData.cs │ │ ├── StandardPage.cs │ │ └── StartPage.cs │ ├── Properties │ │ └── PropertyStringList.cs │ ├── 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 ├── Properties │ └── AssemblyInfo.cs ├── Resources │ └── LanguageFiles │ │ ├── ContentTypeNames.xml │ │ ├── Display.xml │ │ ├── EditorHints.xml │ │ ├── GroupNames.xml │ │ ├── PropertyNames.xml │ │ ├── Views.xml │ │ └── _ReadMe.txt ├── Startup.cs ├── Static │ ├── 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 │ ├── html │ │ └── error.htm │ ├── img │ │ ├── glyphicons-halflings-white.png │ │ └── glyphicons-halflings.png │ ├── js │ │ ├── bootstrap.js │ │ ├── jquery.js │ │ ├── react.bundle.js │ │ └── react.bundle.js.map │ ├── jwplayer │ │ ├── jwplayer.js │ │ ├── player.swf │ │ ├── preview.jpg │ │ └── video.mp4 │ └── react │ │ ├── Clock.jsx │ │ ├── PageListBlock.jsx │ │ ├── ReactNumber.jsx │ │ ├── ThreeKeyFacts.jsx │ │ └── index.js ├── Views │ ├── ArticlePage │ │ └── Index.cshtml │ ├── ContactBlock │ │ └── Index.cshtml │ ├── ImageFile │ │ └── Index.cshtml │ ├── LandingPage │ │ └── Index.cshtml │ ├── NewsPage │ │ └── Index.cshtml │ ├── PageListBlock │ │ └── Index.cshtml │ ├── Preview │ │ └── Index.cshtml │ ├── ProductPage │ │ └── Index.cshtml │ ├── Register │ │ └── Index.cshtml │ ├── SearchPage │ │ └── Index.cshtml │ ├── Shared │ │ ├── Blocks │ │ │ ├── ButtonBlock.cshtml │ │ │ ├── EditorialBlock.cshtml │ │ │ ├── FormBlock.cshtml │ │ │ ├── JumbotronBlockWide.cshtml │ │ │ ├── NoRenderer.cshtml │ │ │ ├── SiteLogotypeBlock.cshtml │ │ │ ├── TeaserBlock.cshtml │ │ │ ├── TeaserBlockWide.cshtml │ │ │ └── ThreeKeyFactsBlock.cshtml │ │ ├── Breadcrumbs.cshtml │ │ ├── DisplayTemplates │ │ │ ├── ContactPage.cshtml │ │ │ ├── DateTime.cshtml │ │ │ ├── Image.cshtml │ │ │ ├── PageListBlock.cshtml │ │ │ ├── ReactNumber.cshtml │ │ │ └── StringList.cshtml │ │ ├── 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 │ ├── VideoFile │ │ └── Index.cshtml │ ├── Web.config │ └── _viewstart.cshtml ├── Web.Debug.config ├── Web.Release.config ├── Web.config ├── favicon.ico ├── gulpfile.js ├── module.config ├── modules │ └── _protected │ │ ├── CMS │ │ ├── CMS.zip │ │ └── web.config │ │ ├── EPiServer.Cms.TinyMce │ │ ├── EPiServer.Cms.TinyMce.zip │ │ └── web.config │ │ ├── EPiServer.Packaging.UI │ │ ├── EPiServer.Packaging.UI.zip │ │ └── web.config │ │ ├── EPiServer.Search.Cms │ │ ├── IndexContent.aspx │ │ └── module.config │ │ ├── EPiServer.XForms │ │ ├── EPiServer.XForms.zip │ │ └── web.config │ │ ├── Shell │ │ ├── Shell.zip │ │ └── web.config │ │ └── repository.config ├── package.json ├── packages.config └── webpack.config.js ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | * text=auto 3 | 4 | 5 | # Explicitly declare text files you want to always be normalized and converted 6 | # to native line endings on checkout. 7 | ## Visual Studio and .NET text files 8 | *.ascx text 9 | *.aspx text 10 | *.cmd text 11 | *.config text 12 | *.cs text diff=csharp 13 | *.cshtml text 14 | *.csproj text 15 | *.master text 16 | *.msbuild text 17 | *.proj text 18 | *.ps1 text 19 | *.psm1 text 20 | *.sln text eol=crlf 21 | *.sql text 22 | *.targets text 23 | *.transform text 24 | *.xml text 25 | 26 | 27 | ## Common web text files 28 | *.css text 29 | *.htm text 30 | *.html text 31 | *.js text 32 | *.less text 33 | *.md text 34 | 35 | ## Bash and Linux text files 36 | *.sh text eol=lf 37 | 38 | 39 | # Denote all files that are truly binary and should not be modified. 40 | ## Visual Studio and .NET binary files 41 | *.dll binary 42 | *.snk binary 43 | 44 | ## Common web binary files 45 | *.gif binary 46 | *.ico binary 47 | *.jpeg binary 48 | *.jpg binary 49 | *.png binary 50 | -------------------------------------------------------------------------------- /AlloyReact/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets" : ["env", "react"] 3 | } -------------------------------------------------------------------------------- /AlloyReact/AlloyReact.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.13 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AlloyReact", "AlloyReact.csproj", "{79CE40FC-6A08-4061-B889-F320D0DEFE31}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {79CE40FC-6A08-4061-B889-F320D0DEFE31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {79CE40FC-6A08-4061-B889-F320D0DEFE31}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {79CE40FC-6A08-4061-B889-F320D0DEFE31}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {79CE40FC-6A08-4061-B889-F320D0DEFE31}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /AlloyReact/App_Data/DefaultSiteContent.episerverdata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/DefaultSiteContent.episerverdata -------------------------------------------------------------------------------- /AlloyReact/App_Data/EPiServerDB_f19fa128.mdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/EPiServerDB_f19fa128.mdf -------------------------------------------------------------------------------- /AlloyReact/App_Data/EPiServerDB_f19fa128_log.ldf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/EPiServerDB_f19fa128_log.ldf -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/0053dd8be47647c09b6d592fddbc90aa/5af56c1426724c0ca388e9c2ea6399d0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/0053dd8be47647c09b6d592fddbc90aa/5af56c1426724c0ca388e9c2ea6399d0.jpg -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/0053dd8be47647c09b6d592fddbc90aa/5af56c1426724c0ca388e9c2ea6399d0_Thumbnail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/0053dd8be47647c09b6d592fddbc90aa/5af56c1426724c0ca388e9c2ea6399d0_Thumbnail.jpg -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/0488427b3c1843eb9671420355f89898/0a3b3bfc98c644458cf557c98a999c1a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/0488427b3c1843eb9671420355f89898/0a3b3bfc98c644458cf557c98a999c1a.jpg -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/05925076ec86458288064a99275b99e8/723817a183ac4ada82e87421f1bf4033.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/05925076ec86458288064a99275b99e8/723817a183ac4ada82e87421f1bf4033.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/18e4d63a23de42da9f75c284b22e2118/ecc95455fbcf46dfb11d8a8515dacf79.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/18e4d63a23de42da9f75c284b22e2118/ecc95455fbcf46dfb11d8a8515dacf79.jpg -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/322815899a3242c0998c56ab05cf3853/4e473727445d48b983ee4b7dd5900e83.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/322815899a3242c0998c56ab05cf3853/4e473727445d48b983ee4b7dd5900e83.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/43e0b8aca4d54992aae25cbf27feba90/4f5f01fe279d4e468b5ac5334b34134f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/43e0b8aca4d54992aae25cbf27feba90/4f5f01fe279d4e468b5ac5334b34134f.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/4416f63d6acd41a7bf4c37aae578c6e2/649294cc796f41929a1965718dffd37a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/4416f63d6acd41a7bf4c37aae578c6e2/649294cc796f41929a1965718dffd37a.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/45db4053ee324a4dbfa198de8a0b0d66/e5b75ca76f414e5a8a7b7ca19ee41841.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/45db4053ee324a4dbfa198de8a0b0d66/e5b75ca76f414e5a8a7b7ca19ee41841.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/4e6dc9529d6343abb1670badfe7077ac/0b29c9305eda43dd83e3981a6ed3a82d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/4e6dc9529d6343abb1670badfe7077ac/0b29c9305eda43dd83e3981a6ed3a82d.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/514777e7c22f4e0ebe7303e5f6a11356/f08006eb5ef94dcb812559722f8de4d0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/514777e7c22f4e0ebe7303e5f6a11356/f08006eb5ef94dcb812559722f8de4d0.jpg -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/54f7f338fed549eab15a80844c15e3cd/7dc53b1842e240979311291983a7ae66.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/54f7f338fed549eab15a80844c15e3cd/7dc53b1842e240979311291983a7ae66.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/5e7cb947aebd451a8a9bab416d608434/7e0637ed94d34711a656619e53f487e8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/5e7cb947aebd451a8a9bab416d608434/7e0637ed94d34711a656619e53f487e8.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/6711854292214695945bae2537a8003f/4e5447acdec14f9d9e64357b785304fd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/6711854292214695945bae2537a8003f/4e5447acdec14f9d9e64357b785304fd.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/738a64528f814c328ece038175fb75c7/75b9ce805d054490bca033587498917a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/738a64528f814c328ece038175fb75c7/75b9ce805d054490bca033587498917a.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/738a64528f814c328ece038175fb75c7/75b9ce805d054490bca033587498917a_Thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/738a64528f814c328ece038175fb75c7/75b9ce805d054490bca033587498917a_Thumbnail.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/83fd8d0600544baa8e1da5c8b075d9bc/1a8e1607451f46508bc92399484aac6b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/83fd8d0600544baa8e1da5c8b075d9bc/1a8e1607451f46508bc92399484aac6b.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/83fd8d0600544baa8e1da5c8b075d9bc/1a8e1607451f46508bc92399484aac6b_Thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/83fd8d0600544baa8e1da5c8b075d9bc/1a8e1607451f46508bc92399484aac6b_Thumbnail.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/8fc23add042144f2a9d2db6e7b2a5b91/eb53bd3a3bd442d98db93e8d2c3fc1af.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/8fc23add042144f2a9d2db6e7b2a5b91/eb53bd3a3bd442d98db93e8d2c3fc1af.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/9102db1c75a541a89154088b78c6d4e2/14a448bd83c44587807a4aab90d730b1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/9102db1c75a541a89154088b78c6d4e2/14a448bd83c44587807a4aab90d730b1.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/95f247ea78b642338a2d796cbbc79f13/1d2e8fda4a944335b2f2fd05c1c0eec7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/95f247ea78b642338a2d796cbbc79f13/1d2e8fda4a944335b2f2fd05c1c0eec7.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/9aa23ec0b8c24c0db7b8627c9698a72b/36444e66f2354570b131138f502e14d4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/9aa23ec0b8c24c0db7b8627c9698a72b/36444e66f2354570b131138f502e14d4.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/9d89c035535043de923324c3796a90b7/78e08f306fc44c03888da8bab14fee3e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/9d89c035535043de923324c3796a90b7/78e08f306fc44c03888da8bab14fee3e.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/9d89c035535043de923324c3796a90b7/78e08f306fc44c03888da8bab14fee3e_Thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/9d89c035535043de923324c3796a90b7/78e08f306fc44c03888da8bab14fee3e_Thumbnail.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/a2b00021b65c4d3c8ba671edd4074200/642752e9ab914dbc8bfbff7b158c1a0b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/a2b00021b65c4d3c8ba671edd4074200/642752e9ab914dbc8bfbff7b158c1a0b.jpg -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/aa3bd220449d40aea77ca5daa38ad91a/c101fa5b5d844132bd6e0662c89fdd91.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/aa3bd220449d40aea77ca5daa38ad91a/c101fa5b5d844132bd6e0662c89fdd91.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/b52964b56069455e8b586e9627aba799/2aedf124d98949208342b1ec395f07c3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/b52964b56069455e8b586e9627aba799/2aedf124d98949208342b1ec395f07c3.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/b52e5a0b7b6c40ce8800b73847e4dc7e/3654f95ce9c243b88a097eafa064ebda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/b52e5a0b7b6c40ce8800b73847e4dc7e/3654f95ce9c243b88a097eafa064ebda.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/b52e5a0b7b6c40ce8800b73847e4dc7e/3654f95ce9c243b88a097eafa064ebda_Thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/b52e5a0b7b6c40ce8800b73847e4dc7e/3654f95ce9c243b88a097eafa064ebda_Thumbnail.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/b6f6dfeb26e64ae68f8b1ac352d7435b/17183bbd93a049bb9911f4baeebeff3e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/b6f6dfeb26e64ae68f8b1ac352d7435b/17183bbd93a049bb9911f4baeebeff3e.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/b943d791c016463782568a7c45dfcb33/7dba176dd85e4d898462b6f11111b163.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/b943d791c016463782568a7c45dfcb33/7dba176dd85e4d898462b6f11111b163.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/bcb01052992e48c49313074e2512c2b9/4744fa764ccc4f51876166ac614abe10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/bcb01052992e48c49313074e2512c2b9/4744fa764ccc4f51876166ac614abe10.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/cacab32eabb6426eb2af20df4878ea59/26d4468ea1a24ddcb287b129546bc9bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/cacab32eabb6426eb2af20df4878ea59/26d4468ea1a24ddcb287b129546bc9bb.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/d261560357dd4573b4c50cc3186ef899/364d4d07c3fa4f8db401ce9504688eec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/d261560357dd4573b4c50cc3186ef899/364d4d07c3fa4f8db401ce9504688eec.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/d655dc5e721049e6813701cf22047a77/ad15c26de9ae4961bb2684c9fc0e3a22.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/d655dc5e721049e6813701cf22047a77/ad15c26de9ae4961bb2684c9fc0e3a22.jpg -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/ddb8ace5bd584ad2aa5b7cce1a6b9869/6598d114649f403494a5e39ae0e52e12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/ddb8ace5bd584ad2aa5b7cce1a6b9869/6598d114649f403494a5e39ae0e52e12.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/ddb8ace5bd584ad2aa5b7cce1a6b9869/6598d114649f403494a5e39ae0e52e12_Thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/ddb8ace5bd584ad2aa5b7cce1a6b9869/6598d114649f403494a5e39ae0e52e12_Thumbnail.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/de77c68c0020437e881872e0809ae65b/e6b6a9b869714ea485f3fd17c38b537f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/de77c68c0020437e881872e0809ae65b/e6b6a9b869714ea485f3fd17c38b537f.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/e88a2e230b1f473c8ffe59f5de341aea/73bc58da26334206b2fee86b6f7c0a65.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/e88a2e230b1f473c8ffe59f5de341aea/73bc58da26334206b2fee86b6f7c0a65.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/f0083115f1f34da28ec301d4e0fa201e/92c46e048fef43d6978fb9afed9f5aaa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/f0083115f1f34da28ec301d4e0fa201e/92c46e048fef43d6978fb9afed9f5aaa.jpg -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/f687a3341cde4af696c7f7d3248b870b/415137265cd848ce8736d489f047c8c3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/f687a3341cde4af696c7f7d3248b870b/415137265cd848ce8736d489f047c8c3.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/f879cb724a5e4e9c980f3ce69ed37f35/ccdc110de0d64864b73fcb36c1b77a53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/f879cb724a5e4e9c980f3ce69ed37f35/ccdc110de0d64864b73fcb36c1b77a53.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/f8f3db6dd82d4084abb126b9cc371a8f/8fbb14eb5b8948fd80cbe9b6484ad482.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/f8f3db6dd82d4084abb126b9cc371a8f/8fbb14eb5b8948fd80cbe9b6484ad482.mp4 -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/f93a55b27d5642d0b4645335fdbad552/bd34e19f5c0f4a2ba1c1c8d5f01808ae.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/f93a55b27d5642d0b4645335fdbad552/bd34e19f5c0f4a2ba1c1c8d5f01808ae.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/faa6473aae9d4171ae0ecfe72b308129/9b4566cb57114c5d82f8b011b3317164.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/faa6473aae9d4171ae0ecfe72b308129/9b4566cb57114c5d82f8b011b3317164.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/fcb0ec7c0e1e45cba14e955d27c02eae/0e06c4e11a794b428ab4f881663b88e8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/fcb0ec7c0e1e45cba14e955d27c02eae/0e06c4e11a794b428ab4f881663b88e8.png -------------------------------------------------------------------------------- /AlloyReact/App_Data/blobs/fea10ef30cbd4548b2d80a2b895b6922/930770cbd8c9437da02cb1c0468945c2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/App_Data/blobs/fea10ef30cbd4548b2d80a2b895b6922/930770cbd8c9437da02cb1c0468945c2.jpg -------------------------------------------------------------------------------- /AlloyReact/Business/AdministratorRegistrationPage.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.ServiceLocation; 2 | using EPiServer.Shell.Security; 3 | using Owin; 4 | using System; 5 | using System.Web; 6 | using System.Web.Mvc; 7 | using System.Web.Routing; 8 | 9 | namespace AlloyReact 10 | { 11 | public static class AdministratorRegistrationPage 12 | { 13 | private static Func _isLocalRequest = () => false; 14 | 15 | private static Lazy _isAnyUserRegistered = new Lazy(() => false); 16 | 17 | private static bool? _isEnabled = null; 18 | 19 | public static bool IsEnabled 20 | { 21 | get 22 | { 23 | if (_isEnabled.HasValue) 24 | { 25 | return _isEnabled.Value; 26 | } 27 | 28 | var showUserRegistration = _isLocalRequest() && !_isAnyUserRegistered.Value; 29 | if (!showUserRegistration) 30 | { 31 | _isEnabled = false; 32 | } 33 | 34 | return showUserRegistration; 35 | } 36 | set 37 | { 38 | _isEnabled = value; 39 | } 40 | } 41 | 42 | public static void UseAdministratorRegistrationPage(this IAppBuilder app, Func isLocalRequest) 43 | { 44 | _isLocalRequest = isLocalRequest; 45 | _isAnyUserRegistered = new Lazy(IsAnyUserRegistered); 46 | GlobalFilters.Filters.Add(new RegistrationActionFilterAttribute()); 47 | if (isLocalRequest()) 48 | { 49 | AddRoute(); 50 | } 51 | } 52 | 53 | private static bool IsAnyUserRegistered() 54 | { 55 | var provider = ServiceLocator.Current.GetInstance(); 56 | int totalUsers = 0; 57 | var res = provider.GetAllUsers(0, 1, out totalUsers); 58 | return totalUsers > 0; 59 | } 60 | 61 | public class RegistrationActionFilterAttribute : ActionFilterAttribute 62 | { 63 | public override void OnActionExecuting(ActionExecutingContext context) 64 | { 65 | var registerUrl = VirtualPathUtility.ToAbsolute("~/Register"); 66 | if (IsEnabled && !context.RequestContext.HttpContext.Request.Path.StartsWith(registerUrl)) 67 | { 68 | context.Result = new RedirectResult(registerUrl); 69 | } 70 | } 71 | } 72 | 73 | static void AddRoute() 74 | { 75 | var routeData = new RouteValueDictionary(); 76 | routeData.Add("Controller", "Register"); 77 | routeData.Add("action", "Index"); 78 | routeData.Add("id", " UrlParameter.Optional"); 79 | RouteTable.Routes.Add("Register", new Route("{controller}/{action}/{id}", routeData, new MvcRouteHandler()) { RouteExistingFiles = false }); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /AlloyReact/Business/Channels/DisplayResolutionBase.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Framework.Localization; 2 | using EPiServer.ServiceLocation; 3 | using EPiServer.Web; 4 | 5 | namespace AlloyReact.Business.Channels 6 | { 7 | /// 8 | /// Base class for all resolution definitions 9 | /// 10 | public abstract class DisplayResolutionBase : IDisplayResolution 11 | { 12 | private Injected LocalizationService { get; set; } 13 | 14 | protected DisplayResolutionBase(string name, int width, int height) 15 | { 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.Service.TryGetString(resurceKey, out value)) 47 | { 48 | value = resurceKey; 49 | } 50 | 51 | return value; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /AlloyReact/Business/Channels/DisplayResolutions.cs: -------------------------------------------------------------------------------- 1 | namespace AlloyReact.Business.Channels 2 | { 3 | /// 4 | /// Defines resolution for desktop displays 5 | /// 6 | public class StandardResolution : DisplayResolutionBase 7 | { 8 | public StandardResolution() : base("/resolutions/standard", 1366, 768) 9 | { 10 | } 11 | } 12 | 13 | /// 14 | /// Defines resolution for a horizontal iPad 15 | /// 16 | public class IpadHorizontalResolution : DisplayResolutionBase 17 | { 18 | public IpadHorizontalResolution() : base("/resolutions/ipadhorizontal", 1024, 768) 19 | { 20 | } 21 | } 22 | 23 | /// 24 | /// Defines resolution for a vertical iPhone 5s 25 | /// 26 | public class IphoneVerticalResolution : DisplayResolutionBase 27 | { 28 | public IphoneVerticalResolution() : base("/resolutions/iphonevertical", 320, 568) 29 | { 30 | } 31 | } 32 | 33 | /// 34 | /// Defines resolution for a vertical Android handheld device 35 | /// 36 | public class AndroidVerticalResolution : DisplayResolutionBase 37 | { 38 | public AndroidVerticalResolution() : base("/resolutions/androidvertical", 480, 800) 39 | { 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /AlloyReact/Business/Channels/MobileChannel.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.WebPages; 3 | using EPiServer.Web; 4 | 5 | namespace AlloyReact.Business.Channels 6 | { 7 | // 8 | //Defines the 'Mobile' content channel 9 | // 10 | public class MobileChannel : DisplayChannel 11 | { 12 | public const string Name = "mobile"; 13 | 14 | public override string ChannelName 15 | { 16 | get 17 | { 18 | return Name; 19 | } 20 | } 21 | 22 | public override string ResolutionId 23 | { 24 | get 25 | { 26 | return typeof(IphoneVerticalResolution).FullName; 27 | } 28 | } 29 | 30 | public override bool IsActive(HttpContextBase context) 31 | { 32 | return context.GetOverriddenBrowser().IsMobileDevice; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /AlloyReact/Business/Channels/WebChannel.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using EPiServer.Web; 3 | 4 | namespace AlloyReact.Business.Channels 5 | { 6 | /// 7 | /// Defines the 'Web' content channel 8 | /// 9 | public class WebChannel : DisplayChannel 10 | { 11 | public override string ChannelName 12 | { 13 | get 14 | { 15 | return "web"; 16 | } 17 | } 18 | 19 | public override bool IsActive(HttpContextBase context) 20 | { 21 | return !context.Request.Browser.IsMobileDevice; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /AlloyReact/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 | using EPiServer; 8 | 9 | namespace AlloyReact.Business 10 | { 11 | /// 12 | /// Extension methods for content 13 | /// 14 | public static class ContentExtensions 15 | { 16 | /// 17 | /// Filters content which should not be visible to the user. 18 | /// 19 | public static IEnumerable FilterForDisplay(this IEnumerable contents, bool requirePageTemplate = false, bool requireVisibleInMenu = false) 20 | where T : IContent 21 | { 22 | var accessFilter = new FilterAccess(); 23 | var publishedFilter = new FilterPublished(); 24 | contents = contents.Where(x => !publishedFilter.ShouldFilter(x) && !accessFilter.ShouldFilter(x)); 25 | if (requirePageTemplate) 26 | { 27 | var templateFilter = ServiceLocator.Current.GetInstance(); 28 | templateFilter.TemplateTypeCategories = TemplateTypeCategories.Page; 29 | contents = contents.Where(x => !templateFilter.ShouldFilter(x)); 30 | } 31 | if (requireVisibleInMenu) 32 | { 33 | contents = contents.Where(x => VisibleInMenu(x)); 34 | } 35 | return contents; 36 | } 37 | 38 | private static bool VisibleInMenu(IContent content) 39 | { 40 | var page = content as PageData; 41 | if (page == null) 42 | { 43 | return true; 44 | } 45 | return page.VisibleInMenu; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /AlloyReact/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 AlloyReact.Business.EditorDescriptors 7 | { 8 | /// 9 | /// Provides a list of options corresponding to ContactPage pages on the site 10 | /// 11 | /// 12 | public class ContactPageSelectionFactory : ISelectionFactory 13 | { 14 | private Injected ContentLocator { get; set; } 15 | 16 | public IEnumerable GetSelections(ExtendedMetadata metadata) 17 | { 18 | var contactPages = ContentLocator.Service.GetContactPages(); 19 | 20 | return new List(contactPages.Select(c => new SelectItem {Value = c.PageLink, Text = c.Name})); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AlloyReact/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 AlloyReact.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 | } 25 | -------------------------------------------------------------------------------- /AlloyReact/Business/EditorDescriptors/StringListEditorDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using EPiServer.Shell.ObjectEditing.EditorDescriptors; 4 | using EPiServer.Shell.ObjectEditing; 5 | 6 | namespace AlloyReact.Business.EditorDescriptors 7 | { 8 | /// 9 | /// Register an editor for StringList properties 10 | /// 11 | [EditorDescriptorRegistration(TargetType = typeof(String[]), UIHint = Global.SiteUIHints.Strings)] 12 | public class StringListEditorDescriptor : EditorDescriptor 13 | { 14 | public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable attributes) 15 | { 16 | ClientEditingClass = "alloy/editors/StringList"; 17 | 18 | base.ModifyMetadata(metadata, attributes); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /AlloyReact/Business/IModifyLayout.cs: -------------------------------------------------------------------------------- 1 | using AlloyReact.Models.ViewModels; 2 | 3 | namespace AlloyReact.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 | -------------------------------------------------------------------------------- /AlloyReact/Business/Initialization/BundleConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Optimization; 2 | using EPiServer.Framework; 3 | using EPiServer.Framework.Initialization; 4 | 5 | namespace AlloyReact.Business.Initialization 6 | { 7 | [InitializableModule] 8 | public class BundleConfig : IInitializableModule 9 | { 10 | public void Initialize(InitializationEngine context) 11 | { 12 | if (context.HostType == HostType.WebApplication) 13 | { 14 | RegisterBundles(BundleTable.Bundles); 15 | } 16 | } 17 | 18 | // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725 19 | public static void RegisterBundles(BundleCollection bundles) 20 | { 21 | bundles.Add(new ScriptBundle("~/bundles/js").Include( 22 | "~/Static/js/jquery.js", //jquery.js can be removed and linked from CDN instead, we use a local one for demo purposes without internet connectionzz 23 | "~/Static/js/bootstrap.js")); 24 | 25 | bundles.Add(new StyleBundle("~/bundles/css") 26 | .Include("~/Static/css/bootstrap.css", new CssRewriteUrlTransform()) 27 | .Include("~/Static/css/bootstrap-responsive.css") 28 | .Include("~/Static/css/media.css") 29 | .Include("~/Static/css/style.css", new CssRewriteUrlTransform()) 30 | .Include("~/Static/css/editmode.css")); 31 | } 32 | 33 | public void Uninitialize(InitializationEngine context) 34 | { 35 | } 36 | 37 | public void Preload(string[] parameters) 38 | { 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /AlloyReact/Business/Initialization/CustomizedRenderingInitialization.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using EPiServer.Framework; 3 | using EPiServer.Framework.Initialization; 4 | using EPiServer.ServiceLocation; 5 | using AlloyReact.Business.Rendering; 6 | using EPiServer.Web; 7 | 8 | namespace AlloyReact.Business.Initialization 9 | { 10 | /// 11 | /// Module for customizing templates and rendering. 12 | /// 13 | [ModuleDependency(typeof(EPiServer.Web.InitializationModule))] 14 | public class CustomizedRenderingInitialization : IInitializableModule 15 | { 16 | public void Initialize(InitializationEngine context) 17 | { 18 | //Add custom view engine allowing partials to be placed in additional locations 19 | //Note that we add it first in the list to optimize view resolving when using DisplayFor/PropertyFor 20 | ViewEngines.Engines.Insert(0, new SiteViewEngine()); 21 | 22 | context.Locate.TemplateResolver() 23 | .TemplateResolved += TemplateCoordinator.OnTemplateResolved; 24 | } 25 | 26 | public void Uninitialize(InitializationEngine context) 27 | { 28 | ServiceLocator.Current.GetInstance() 29 | .TemplateResolved -= TemplateCoordinator.OnTemplateResolved; 30 | } 31 | 32 | public void Preload(string[] parameters) 33 | { 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /AlloyReact/Business/Initialization/DependencyResolverInitialization.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using EPiServer.Framework; 3 | using EPiServer.Framework.Initialization; 4 | using EPiServer.ServiceLocation; 5 | using AlloyReact.Business.Rendering; 6 | using EPiServer.Web.Mvc; 7 | using EPiServer.Web.Mvc.Html; 8 | 9 | namespace AlloyReact.Business.Initialization 10 | { 11 | [InitializableModule] 12 | public class DependencyResolverInitialization : IConfigurableModule 13 | { 14 | public void ConfigureContainer(ServiceConfigurationContext context) 15 | { 16 | //Implementations for custom interfaces can be registered here. 17 | 18 | context.ConfigurationComplete += (o, e) => 19 | { 20 | //Register custom implementations that should be used in favour of the default implementations 21 | context.Services.AddTransient() 22 | .AddTransient(); 23 | }; 24 | } 25 | 26 | public void Initialize(InitializationEngine context) 27 | { 28 | DependencyResolver.SetResolver(new ServiceLocatorDependencyResolver(context.Locate.Advanced)); 29 | } 30 | 31 | public void Uninitialize(InitializationEngine context) 32 | { 33 | } 34 | 35 | public void Preload(string[] parameters) 36 | { 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /AlloyReact/Business/Initialization/DisplayModesInitialization.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Web; 3 | using System.Web.WebPages; 4 | using EPiServer.Framework; 5 | using EPiServer.Framework.Initialization; 6 | using EPiServer.ServiceLocation; 7 | using AlloyReact.Business.Channels; 8 | using EPiServer.Web; 9 | 10 | namespace AlloyReact.Business.Initialization 11 | { 12 | /// 13 | /// Adds a new display mode for mobile which is active if the mobile channel is active in addition to if the request is from a mobile device (like the default one) 14 | /// 15 | /// 16 | /// It's also possible to map a display mode as a channel through the DisplayChannelService.RegisterDisplayMode() method. 17 | /// Adding channels that way does not however enable specifying ResolutionId which we want to do for the mobile channel. 18 | /// 19 | [ModuleDependency(typeof(EPiServer.Web.InitializationModule))] 20 | public class DisplayModesInitialization : IInitializableModule 21 | { 22 | public void Initialize(InitializationEngine context) 23 | { 24 | var mobileChannelDisplayMode = new DefaultDisplayMode("mobile") 25 | { 26 | ContextCondition = IsMobileDisplayModeActive 27 | }; 28 | DisplayModeProvider.Instance.Modes.Insert(0, mobileChannelDisplayMode); 29 | } 30 | 31 | private static bool IsMobileDisplayModeActive(HttpContextBase httpContext) 32 | { 33 | if (httpContext.GetOverriddenBrowser().IsMobileDevice) 34 | { 35 | return true; 36 | } 37 | var displayChannelService = ServiceLocator.Current.GetInstance(); 38 | return displayChannelService.GetActiveChannels(httpContext).Any(x => x.ChannelName == MobileChannel.Name); 39 | } 40 | 41 | public void Uninitialize(InitializationEngine context) 42 | { 43 | } 44 | 45 | public void Preload(string[] parameters) 46 | { 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AlloyReact/Business/Initialization/DisplayRegistryInitialization.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Framework; 2 | using EPiServer.Framework.Initialization; 3 | using EPiServer.ServiceLocation; 4 | using EPiServer.Web; 5 | using System.Collections.Generic; 6 | using System.Web.Mvc; 7 | 8 | namespace AlloyReact.Business.Initialization 9 | { 10 | [InitializableModule] 11 | [ModuleDependency(typeof(EPiServer.Web.InitializationModule))] 12 | public class DisplayRegistryInitialization : IInitializableModule 13 | { 14 | public void Initialize(InitializationEngine context) 15 | { 16 | if (context.HostType == HostType.WebApplication) 17 | { 18 | // Register Display Options 19 | var options = ServiceLocator.Current.GetInstance(); 20 | options 21 | .Add("full", "/displayoptions/full", Global.ContentAreaTags.FullWidth, "", "epi-icon__layout--full") 22 | .Add("wide", "/displayoptions/wide", Global.ContentAreaTags.TwoThirdsWidth, "", "epi-icon__layout--two-thirds") 23 | .Add("narrow", "/displayoptions/narrow", Global.ContentAreaTags.OneThirdWidth, "", "epi-icon__layout--one-third"); 24 | 25 | AreaRegistration.RegisterAllAreas(); 26 | 27 | } 28 | } 29 | 30 | public void Preload(string[] parameters){} 31 | 32 | public void Uninitialize(InitializationEngine context){} 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /AlloyReact/Business/Initialization/FilterConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using EPiServer.Framework; 3 | using EPiServer.Framework.Initialization; 4 | using EPiServer.ServiceLocation; 5 | 6 | namespace AlloyReact.Business.Initialization 7 | { 8 | /// 9 | /// Module for registering filters which will be applied to controller actions. 10 | /// 11 | [ModuleDependency(typeof(EPiServer.Web.InitializationModule))] 12 | public class FilterConfig : IInitializableModule 13 | { 14 | public void Initialize(InitializationEngine context) 15 | { 16 | GlobalFilters.Filters.Add(ServiceLocator.Current.GetInstance()); 17 | } 18 | 19 | public void Uninitialize(InitializationEngine context) 20 | { 21 | } 22 | 23 | public void Preload(string[] parameters) 24 | { 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AlloyReact/Business/PageContextActionFilter.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using AlloyReact.Models.Pages; 3 | using AlloyReact.Models.ViewModels; 4 | using EPiServer.Web.Routing; 5 | 6 | namespace AlloyReact.Business 7 | { 8 | /// 9 | /// Intercepts actions with view models of type IPageViewModel and populates the view models 10 | /// Layout and Section properties. 11 | /// 12 | /// 13 | /// This filter frees controllers for pages from having to care about common context needed by layouts 14 | /// and other page framework components allowing the controllers to focus on the specifics for the page types 15 | /// and actions that they handle. 16 | /// 17 | public class PageContextActionFilter : IResultFilter 18 | { 19 | private readonly PageViewContextFactory _contextFactory; 20 | public PageContextActionFilter(PageViewContextFactory contextFactory) 21 | { 22 | _contextFactory = contextFactory; 23 | } 24 | 25 | public void OnResultExecuting(ResultExecutingContext filterContext) 26 | { 27 | var viewModel = filterContext.Controller.ViewData.Model; 28 | 29 | var model = viewModel as IPageViewModel; 30 | if (model != null) 31 | { 32 | var currentContentLink = filterContext.RequestContext.GetContentLink(); 33 | 34 | var layoutModel = model.Layout ?? _contextFactory.CreateLayoutModel(currentContentLink, filterContext.RequestContext); 35 | 36 | var layoutController = filterContext.Controller as IModifyLayout; 37 | if(layoutController != null) 38 | { 39 | layoutController.ModifyLayout(layoutModel); 40 | } 41 | 42 | model.Layout = layoutModel; 43 | 44 | if (model.Section == null) 45 | { 46 | model.Section = _contextFactory.GetSection(currentContentLink); 47 | } 48 | } 49 | } 50 | 51 | public void OnResultExecuted(ResultExecutedContext filterContext) 52 | { 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /AlloyReact/Business/PageTypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EPiServer.DataAbstraction; 3 | using EPiServer.ServiceLocation; 4 | 5 | namespace AlloyReact.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 | -------------------------------------------------------------------------------- /AlloyReact/Business/PageViewContextFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Web; 3 | using System.Web.Mvc; 4 | using System.Web.Routing; 5 | using System.Web.Security; 6 | using AlloyReact.Models.Pages; 7 | using AlloyReact.Models.ViewModels; 8 | using EPiServer; 9 | using EPiServer.Core; 10 | using EPiServer.Data; 11 | using EPiServer.Web; 12 | using EPiServer.Web.Routing; 13 | 14 | namespace AlloyReact.Business 15 | { 16 | public class PageViewContextFactory 17 | { 18 | private readonly IContentLoader _contentLoader; 19 | private readonly UrlResolver _urlResolver; 20 | private readonly IDatabaseMode _databaseMode; 21 | 22 | public PageViewContextFactory(IContentLoader contentLoader, UrlResolver urlResolver, IDatabaseMode databaseMode) 23 | { 24 | _contentLoader = contentLoader; 25 | _urlResolver = urlResolver; 26 | _databaseMode = databaseMode; 27 | } 28 | 29 | public virtual LayoutModel CreateLayoutModel(ContentReference currentContentLink, RequestContext requestContext) 30 | { 31 | var startPageContentLink = SiteDefinition.Current.StartPage; 32 | 33 | // Use the content link with version information when editing the startpage, 34 | // otherwise the published version will be used when rendering the props below. 35 | if (currentContentLink.CompareToIgnoreWorkID(startPageContentLink)) 36 | { 37 | startPageContentLink = currentContentLink; 38 | } 39 | 40 | var startPage = _contentLoader.Get(startPageContentLink); 41 | 42 | return new LayoutModel 43 | { 44 | Logotype = startPage.SiteLogotype, 45 | LogotypeLinkUrl = new MvcHtmlString(_urlResolver.GetUrl(SiteDefinition.Current.StartPage)), 46 | ProductPages = startPage.ProductPageLinks, 47 | CompanyInformationPages = startPage.CompanyInformationPageLinks, 48 | NewsPages = startPage.NewsPageLinks, 49 | CustomerZonePages = startPage.CustomerZonePageLinks, 50 | LoggedIn = requestContext.HttpContext.User.Identity.IsAuthenticated, 51 | LoginUrl = new MvcHtmlString(GetLoginUrl(currentContentLink)), 52 | SearchActionUrl = new MvcHtmlString(EPiServer.Web.Routing.UrlResolver.Current.GetUrl(startPage.SearchPageLink)), 53 | IsInReadonlyMode = _databaseMode.DatabaseMode == DatabaseMode.ReadOnly 54 | }; 55 | } 56 | 57 | private string GetLoginUrl(ContentReference returnToContentLink) 58 | { 59 | return string.Format( 60 | "{0}?ReturnUrl={1}", 61 | (FormsAuthentication.IsEnabled ? FormsAuthentication.LoginUrl : VirtualPathUtility.ToAbsolute(Global.AppRelativeLoginPath)), 62 | _urlResolver.GetUrl(returnToContentLink)); 63 | } 64 | 65 | public virtual IContent GetSection(ContentReference contentLink) 66 | { 67 | var currentContent = _contentLoader.Get(contentLink); 68 | if (currentContent.ParentLink != null && currentContent.ParentLink.CompareToIgnoreWorkID(SiteDefinition.Current.StartPage)) 69 | { 70 | return currentContent; 71 | } 72 | 73 | return _contentLoader.GetAncestors(contentLink) 74 | .OfType() 75 | .SkipWhile(x => x.ParentLink == null || !x.ParentLink.CompareToIgnoreWorkID(SiteDefinition.Current.StartPage)) 76 | .FirstOrDefault(); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /AlloyReact/Business/Rendering/AlloyContentAreaRenderer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Mvc; 3 | using EPiServer.Core; 4 | using EPiServer.Core.Html.StringParsing; 5 | using EPiServer.Web; 6 | using EPiServer.Web.Mvc; 7 | using EPiServer.Web.Mvc.Html; 8 | using EPiServer; 9 | 10 | namespace AlloyReact.Business.Rendering 11 | { 12 | /// 13 | /// Extends the default to apply custom CSS classes to each . 14 | /// 15 | public class AlloyContentAreaRenderer : ContentAreaRenderer 16 | { 17 | protected override string GetContentAreaItemCssClass(HtmlHelper htmlHelper, ContentAreaItem contentAreaItem) 18 | { 19 | var tag = GetContentAreaItemTemplateTag(htmlHelper, contentAreaItem); 20 | return string.Format("block {0} {1} {2}", 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 | -------------------------------------------------------------------------------- /AlloyReact/Business/Rendering/IContainerPage.cs: -------------------------------------------------------------------------------- 1 | namespace AlloyReact.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 | -------------------------------------------------------------------------------- /AlloyReact/Business/Rendering/ICustomCssInContentArea.cs: -------------------------------------------------------------------------------- 1 | namespace AlloyReact.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 | -------------------------------------------------------------------------------- /AlloyReact/Business/Rendering/SiteViewEngine.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Web.Mvc; 3 | 4 | namespace AlloyReact.Business.Rendering 5 | { 6 | /// 7 | /// Extends the Razor view engine to include the folders ~/Views/Shared/Blocks/ and ~/Views/Shared/PagePartials/ 8 | /// when looking for partial views. 9 | /// 10 | public class SiteViewEngine : RazorViewEngine 11 | { 12 | private static readonly string[] AdditionalPartialViewFormats = new[] 13 | { 14 | TemplateCoordinator.BlockFolder + "{0}.cshtml", 15 | TemplateCoordinator.PagePartialsFolder + "{0}.cshtml" 16 | }; 17 | 18 | public SiteViewEngine() 19 | { 20 | PartialViewLocationFormats = PartialViewLocationFormats.Union(AdditionalPartialViewFormats).ToArray(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AlloyReact/Business/SearchService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Web; 3 | using EPiServer.Core; 4 | using EPiServer.Search; 5 | using EPiServer.Search.Queries; 6 | using EPiServer.Search.Queries.Lucene; 7 | using EPiServer.Security; 8 | using EPiServer; 9 | using EPiServer.ServiceLocation; 10 | 11 | namespace AlloyReact.Business 12 | { 13 | public class SearchService 14 | { 15 | private readonly SearchHandler _searchHandler; 16 | private readonly IContentLoader _contentLoader; 17 | 18 | public SearchService(SearchHandler searchHandler, IContentLoader contentLoader) 19 | { 20 | _searchHandler = searchHandler; 21 | _contentLoader = contentLoader; 22 | } 23 | 24 | public virtual bool IsActive 25 | { 26 | get { return ServiceLocator.Current.GetInstance().Active; } 27 | } 28 | 29 | public virtual SearchResults Search(string searchText, IEnumerable searchRoots, HttpContextBase context, string languageBranch, int maxResults) 30 | { 31 | var query = CreateQuery(searchText, searchRoots, context, languageBranch); 32 | return _searchHandler.GetSearchResults(query, 1, maxResults); 33 | } 34 | 35 | private IQueryExpression CreateQuery(string searchText, IEnumerable searchRoots, HttpContextBase context, string languageBranch) 36 | { 37 | //Main query which groups other queries. Each query added 38 | //must match in order for a page or file to be returned. 39 | var query = new GroupQuery(LuceneOperator.AND); 40 | 41 | //Add free text query to the main query 42 | query.QueryExpressions.Add(new FieldQuery(searchText)); 43 | 44 | //Search for pages using the provided language 45 | var pageTypeQuery = new GroupQuery(LuceneOperator.AND); 46 | pageTypeQuery.QueryExpressions.Add(new ContentQuery()); 47 | pageTypeQuery.QueryExpressions.Add(new FieldQuery(languageBranch, Field.Culture)); 48 | 49 | //Search for media without languages 50 | var contentTypeQuery = new GroupQuery(LuceneOperator.OR); 51 | contentTypeQuery.QueryExpressions.Add(new ContentQuery()); 52 | contentTypeQuery.QueryExpressions.Add(pageTypeQuery); 53 | 54 | query.QueryExpressions.Add(contentTypeQuery); 55 | 56 | //Create and add query which groups type conditions using OR 57 | var typeQueries = new GroupQuery(LuceneOperator.OR); 58 | query.QueryExpressions.Add(typeQueries); 59 | 60 | foreach (var root in searchRoots) 61 | { 62 | var contentRootQuery = new VirtualPathQuery(); 63 | contentRootQuery.AddContentNodes(root); 64 | typeQueries.QueryExpressions.Add(contentRootQuery); 65 | } 66 | 67 | var accessRightsQuery = new AccessControlListQuery(); 68 | accessRightsQuery.AddAclForUser(PrincipalInfo.Current, context); 69 | query.QueryExpressions.Add(accessRightsQuery); 70 | 71 | return query; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /AlloyReact/Business/ServiceLocatorDependencyResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web.Mvc; 5 | using EPiServer.ServiceLocation; 6 | 7 | namespace AlloyReact.Business 8 | { 9 | public class ServiceLocatorDependencyResolver : IDependencyResolver 10 | { 11 | readonly IServiceLocator _serviceLocator; 12 | 13 | public ServiceLocatorDependencyResolver(IServiceLocator serviceLocator) 14 | { 15 | _serviceLocator = serviceLocator; 16 | } 17 | 18 | public object GetService(Type serviceType) 19 | { 20 | if (serviceType.IsInterface || serviceType.IsAbstract) 21 | { 22 | return GetInterfaceService(serviceType); 23 | } 24 | return GetConcreteService(serviceType); 25 | } 26 | 27 | private object GetConcreteService(Type serviceType) 28 | { 29 | try 30 | { 31 | // Can't use TryGetInstance here because it won’t create concrete types 32 | return _serviceLocator.GetInstance(serviceType); 33 | } 34 | catch (ActivationException) 35 | { 36 | return null; 37 | } 38 | } 39 | 40 | private object GetInterfaceService(Type serviceType) 41 | { 42 | object instance; 43 | return _serviceLocator.TryGetExistingInstance(serviceType, out instance) ? instance : null; 44 | } 45 | 46 | public IEnumerable GetServices(Type serviceType) 47 | { 48 | return _serviceLocator.GetAllInstances(serviceType).Cast(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /AlloyReact/Business/UIDescriptors/ContainerPageUIDescriptor.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Editor; 2 | using EPiServer.Shell; 3 | using AlloyReact.Models.Pages; 4 | 5 | namespace AlloyReact.Business.UIDescriptors 6 | { 7 | /// 8 | /// Describes how the UI should appear for content. 9 | /// 10 | [UIDescriptorRegistration] 11 | public class ContainerPageUIDescriptor : UIDescriptor 12 | { 13 | public ContainerPageUIDescriptor() 14 | : base(ContentTypeCssClassNames.Container) 15 | { 16 | DefaultView = CmsViewNames.AllPropertiesView; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AlloyReact/ClientResources/Images/icons/layoutIcons24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/ClientResources/Images/icons/layoutIcons24x24.png -------------------------------------------------------------------------------- /AlloyReact/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 | } -------------------------------------------------------------------------------- /AlloyReact/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 | } -------------------------------------------------------------------------------- /AlloyReact/Controllers/ContactBlockController.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Mvc; 3 | using EPiServer.Core; 4 | using AlloyReact.Helpers; 5 | using AlloyReact.Models.Blocks; 6 | using AlloyReact.Models.Pages; 7 | using AlloyReact.Models.ViewModels; 8 | using EPiServer.Web; 9 | using EPiServer.Web.Mvc; 10 | using EPiServer; 11 | 12 | namespace AlloyReact.Controllers 13 | { 14 | public class ContactBlockController : BlockController 15 | { 16 | private readonly IContentLoader _contentLoader; 17 | private readonly IPermanentLinkMapper _permanentLinkMapper; 18 | 19 | public ContactBlockController(IContentLoader contentLoader, IPermanentLinkMapper permanentLinkMapper) 20 | { 21 | _contentLoader = contentLoader; 22 | _permanentLinkMapper = permanentLinkMapper; 23 | } 24 | 25 | public override ActionResult Index(ContactBlock currentBlock) 26 | { 27 | ContactPage contactPage = null; 28 | if(!ContentReference.IsNullOrEmpty(currentBlock.ContactPageLink)) 29 | { 30 | contactPage = _contentLoader.Get(currentBlock.ContactPageLink); 31 | } 32 | 33 | var linkUrl = GetLinkUrl(currentBlock); 34 | 35 | var model = new ContactBlockModel 36 | { 37 | Heading = currentBlock.Heading, 38 | Image = currentBlock.Image, 39 | ContactPage = contactPage, 40 | LinkUrl = GetLinkUrl(currentBlock), 41 | LinkText = currentBlock.LinkText, 42 | ShowLink = linkUrl != null 43 | }; 44 | 45 | //As we're using a separate view model with different property names than the content object 46 | //we connect the view models properties with the content objects so that they can be edited. 47 | ViewData.GetEditHints() 48 | .AddConnection(x => x.Heading, x => x.Heading) 49 | .AddConnection(x => x.Image, x => x.Image) 50 | .AddConnection(x => (object) x.ContactPage, x => (object) x.ContactPageLink) 51 | .AddConnection(x => x.LinkText, x => x.LinkText); 52 | 53 | return PartialView(model); 54 | } 55 | 56 | private IHtmlString GetLinkUrl(ContactBlock contactBlock) 57 | { 58 | if (contactBlock.LinkUrl != null && !contactBlock.LinkUrl.IsEmpty()) 59 | { 60 | var linkUrl = contactBlock.LinkUrl.ToString(); 61 | 62 | //If the url maps to a page on the site we convert it from the internal (permanent, GUID-like) format 63 | //to the human readable and pretty public format 64 | var linkMap = _permanentLinkMapper.Find(new UrlBuilder(linkUrl)); 65 | if (linkMap != null && !ContentReference.IsNullOrEmpty(linkMap.ContentReference)) 66 | { 67 | return Url.PageLinkUrl(linkMap.ContentReference); 68 | } 69 | 70 | return new MvcHtmlString(contactBlock.LinkUrl.ToString()); 71 | } 72 | 73 | return null; 74 | } 75 | 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /AlloyReact/Controllers/DefaultPageController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Mvc; 3 | using EPiServer; 4 | using EPiServer.Framework.DataAnnotations; 5 | using AlloyReact.Models.Pages; 6 | using AlloyReact.Models.ViewModels; 7 | 8 | namespace AlloyReact.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. Alterntively 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 | -------------------------------------------------------------------------------- /AlloyReact/Controllers/ImageFileController.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using AlloyReact.Models.Media; 3 | using AlloyReact.Models.ViewModels; 4 | using EPiServer.Web.Mvc; 5 | using EPiServer.Web.Routing; 6 | 7 | namespace AlloyReact.Controllers 8 | { 9 | /// 10 | /// Controller for the image file. 11 | /// 12 | public class ImageFileController : PartialContentController 13 | { 14 | private readonly UrlResolver _urlResolver; 15 | 16 | public ImageFileController(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 | public override ActionResult Index(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 PartialView(model); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /AlloyReact/Controllers/PageControllerBase.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using AlloyReact.Business; 3 | using AlloyReact.Models.Pages; 4 | using AlloyReact.Models.ViewModels; 5 | using EPiServer.Web.Mvc; 6 | using EPiServer.Shell.Security; 7 | 8 | namespace AlloyReact.Controllers 9 | { 10 | /// 11 | /// All controllers that renders pages should inherit from this class so that we can 12 | /// apply action filters, such as for output caching site wide, should we want to. 13 | /// 14 | public abstract class PageControllerBase : PageController, IModifyLayout 15 | where T : SitePageData 16 | { 17 | 18 | protected EPiServer.ServiceLocation.Injected UISignInManager; 19 | 20 | /// 21 | /// Signs out the current user and redirects to the Index action of the same controller. 22 | /// 23 | /// 24 | /// There's a log out link in the footer which should redirect the user to the same page. 25 | /// As we don't have a specific user/account/login controller but rely on the login URL for 26 | /// forms authentication for login functionality we add an action for logging out to all 27 | /// controllers inheriting from this class. 28 | /// 29 | public ActionResult Logout() 30 | { 31 | UISignInManager.Service.SignOut(); 32 | return RedirectToAction("Index"); 33 | } 34 | 35 | public virtual void ModifyLayout(LayoutModel layoutModel) 36 | { 37 | var page = PageContext.Page as SitePageData; 38 | if(page != null) 39 | { 40 | layoutModel.HideHeader = page.HideSiteHeader; 41 | layoutModel.HideFooter = page.HideSiteFooter; 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /AlloyReact/Controllers/StartPageController.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using AlloyReact.Models.Pages; 3 | using AlloyReact.Models.ViewModels; 4 | using EPiServer.Web; 5 | using EPiServer.Web.Mvc; 6 | 7 | namespace AlloyReact.Controllers 8 | { 9 | public class StartPageController : PageControllerBase 10 | { 11 | public ActionResult 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 | -------------------------------------------------------------------------------- /AlloyReact/Controllers/VideoFileController.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using AlloyReact.Models.Media; 3 | using AlloyReact.Models.ViewModels; 4 | using EPiServer.Web.Mvc; 5 | using EPiServer.Web.Routing; 6 | using System; 7 | using EPiServer.Core; 8 | 9 | namespace AlloyReact.Controllers 10 | { 11 | /// 12 | /// Controller for the video file. 13 | /// 14 | public class VideoFileController : PartialContentController 15 | { 16 | private readonly UrlResolver _urlResolver; 17 | 18 | public VideoFileController(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 | public override ActionResult Index(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 PartialView(model); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AlloyReact/EPiServerLog.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 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /AlloyReact/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Language="C#" Inherits="AlloyReact.EPiServerApplication" %> -------------------------------------------------------------------------------- /AlloyReact/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Mvc; 3 | 4 | namespace AlloyReact 5 | { 6 | public class EPiServerApplication : EPiServer.Global 7 | { 8 | protected void Application_Start() 9 | { 10 | AreaRegistration.RegisterAllAreas(); 11 | 12 | //Tip: Want to call the EPiServer API on startup? Add an initialization module instead (Add -> New Item.. -> EPiServer -> Initialization Module) 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /AlloyReact/Global.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.DataAnnotations; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace AlloyReact 6 | { 7 | 8 | public class Global 9 | { 10 | public static readonly string LoginPath = "/util/login.aspx"; 11 | public static readonly string AppRelativeLoginPath = string.Format("~{0}", LoginPath); 12 | 13 | /// 14 | /// Group names for content types and properties 15 | /// 16 | [GroupDefinitions()] 17 | public static class GroupNames 18 | { 19 | [Display(Name = "Contact", Order = 1)] 20 | public const string Contact = "Contact"; 21 | 22 | [Display(Name = "Default", Order = 2)] 23 | public const string Default = "Default"; 24 | 25 | [Display(Name = "Metadata", Order = 3)] 26 | public const string MetaData = "Metadata"; 27 | 28 | [Display(Name = "News", Order = 4)] 29 | public const string News = "News"; 30 | 31 | [Display(Name = "Products", Order = 5)] 32 | public const string Products = "Products"; 33 | 34 | [Display(Name = "SiteSettings", Order = 6)] 35 | public const string SiteSettings = "SiteSettings"; 36 | 37 | [Display(Name = "Specialized", Order = 7)] 38 | public const string Specialized = "Specialized"; 39 | } 40 | 41 | /// 42 | /// Tags to use for the main widths used in the Bootstrap HTML framework 43 | /// 44 | public static class ContentAreaTags 45 | { 46 | public const string FullWidth = "span12"; 47 | public const string TwoThirdsWidth = "span8"; 48 | public const string HalfWidth = "span6"; 49 | public const string OneThirdWidth = "span4"; 50 | public const string NoRenderer = "norenderer"; 51 | } 52 | 53 | /// 54 | /// Main widths used in the Bootstrap HTML framework 55 | /// 56 | public static class ContentAreaWidths 57 | { 58 | public const int FullWidth = 12; 59 | public const int TwoThirdsWidth = 8; 60 | public const int HalfWidth = 6; 61 | public const int OneThirdWidth = 4; 62 | } 63 | 64 | public static Dictionary ContentAreaTagWidths = new Dictionary 65 | { 66 | { ContentAreaTags.FullWidth, ContentAreaWidths.FullWidth }, 67 | { ContentAreaTags.TwoThirdsWidth, ContentAreaWidths.TwoThirdsWidth }, 68 | { ContentAreaTags.HalfWidth, ContentAreaWidths.HalfWidth }, 69 | { ContentAreaTags.OneThirdWidth, ContentAreaWidths.OneThirdWidth } 70 | }; 71 | 72 | /// 73 | /// Names used for UIHint attributes to map specific rendering controls to page properties 74 | /// 75 | public static class SiteUIHints 76 | { 77 | public const string Contact = "contact"; 78 | public const string Strings = "StringList"; 79 | } 80 | 81 | /// 82 | /// Virtual path to folder with static graphics, such as "~/Static/gfx/" 83 | /// 84 | public const string StaticGraphicsFolderPath = "~/Static/gfx/"; 85 | } 86 | } 87 | 88 | -------------------------------------------------------------------------------- /AlloyReact/Helpers/CategorizableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using EPiServer; 4 | using EPiServer.Core; 5 | using EPiServer.DataAbstraction; 6 | using EPiServer.ServiceLocation; 7 | 8 | namespace AlloyReact.Helpers 9 | { 10 | /// 11 | /// Provides extension methods for categorizable content 12 | /// 13 | /// ICategorizable content includes for example pages and blocks. 14 | public static class CategorizableExtensions 15 | { 16 | /// 17 | /// Returns the CSS classes (if any) associated with the theme(s) of the content, as decided by its categories 18 | /// 19 | /// 20 | /// CSS classes associated with the content's theme(s), or an empty string array if no theme is applicable 21 | /// Content's categorization may map to more than one theme. This method assumes there are website categories called "Meet", "Track", and "Plan" 22 | public static string[] GetThemeCssClassNames(this ICategorizable content) 23 | { 24 | if (content.Category == null) 25 | { 26 | return new string[0]; 27 | } 28 | 29 | var cssClasses = new HashSet(); // Although with some overhead, a HashSet allows us to ensure we never add a CSS class more than once 30 | var categoryRepository = ServiceLocator.Current.GetInstance(); 31 | 32 | foreach (var categoryName in content.Category.Select(category => categoryRepository.Get(category).Name.ToLower())) 33 | { 34 | switch (categoryName) 35 | { 36 | case "meet": 37 | cssClasses.Add("theme1"); 38 | break; 39 | case "track": 40 | cssClasses.Add("theme2"); 41 | break; 42 | case "plan": 43 | cssClasses.Add("theme3"); 44 | break; 45 | } 46 | } 47 | 48 | return cssClasses.ToArray(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /AlloyReact/Helpers/UrlHelpers.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Mvc; 3 | using System.Web.Routing; 4 | using EPiServer.Core; 5 | using EPiServer.Globalization; 6 | using EPiServer.ServiceLocation; 7 | using EPiServer.Web.Routing; 8 | using EPiServer; 9 | 10 | namespace AlloyReact.Helpers 11 | { 12 | public static class UrlHelpers 13 | { 14 | /// 15 | /// Returns the target URL for a ContentReference. Respects the page's shortcut setting 16 | /// so if the page is set as a shortcut to another page or an external URL that URL 17 | /// will be returned. 18 | /// 19 | public static IHtmlString PageLinkUrl(this UrlHelper urlHelper, ContentReference contentLink) 20 | { 21 | if(ContentReference.IsNullOrEmpty(contentLink)) 22 | { 23 | return MvcHtmlString.Empty; 24 | } 25 | 26 | var contentLoader = ServiceLocator.Current.GetInstance(); 27 | var page = contentLoader.Get(contentLink); 28 | 29 | return PageLinkUrl(urlHelper, page); 30 | } 31 | 32 | /// 33 | /// Returns the target URL for a page. Respects the page's shortcut setting 34 | /// so if the page is set as a shortcut to another page or an external URL that URL 35 | /// will be returned. 36 | /// 37 | public static IHtmlString PageLinkUrl(this UrlHelper urlHelper, PageData page) 38 | { 39 | var urlResolver = ServiceLocator.Current.GetInstance(); 40 | switch (page.LinkType) 41 | { 42 | case PageShortcutType.Normal: 43 | case PageShortcutType.FetchData: 44 | return new MvcHtmlString(urlResolver.GetUrl(page.ContentLink)); 45 | 46 | case PageShortcutType.Shortcut: 47 | var shortcutProperty = page.Property["PageShortcutLink"] as PropertyPageReference; 48 | if (shortcutProperty != null && !ContentReference.IsNullOrEmpty(shortcutProperty.ContentLink)) 49 | { 50 | return urlHelper.PageLinkUrl(shortcutProperty.ContentLink); 51 | } 52 | break; 53 | 54 | case PageShortcutType.External: 55 | return new MvcHtmlString(page.LinkURL); 56 | } 57 | return MvcHtmlString.Empty; 58 | } 59 | 60 | public static RouteValueDictionary GetPageRoute(this RequestContext requestContext, ContentReference contentLink) 61 | { 62 | var values = new RouteValueDictionary(); 63 | values[RoutingConstants.NodeKey] = contentLink; 64 | values[RoutingConstants.LanguageKey] = ContentLanguage.PreferredCulture.Name; 65 | return values; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /AlloyReact/Models/Blocks/ButtonBlock.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using EPiServer.DataAbstraction; 3 | using EPiServer; 4 | 5 | namespace AlloyReact.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 | } 23 | -------------------------------------------------------------------------------- /AlloyReact/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 AlloyReact.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 | } 53 | -------------------------------------------------------------------------------- /AlloyReact/Models/Blocks/EditorialBlock.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using EPiServer.Core; 3 | using EPiServer.DataAbstraction; 4 | using EPiServer.DataAnnotations; 5 | 6 | namespace AlloyReact.Models.Blocks 7 | { 8 | /// 9 | /// Used to insert editorial content edited using a rich-text editor 10 | /// 11 | [SiteContentType( 12 | GUID = "67F617A4-2175-4360-975E-75EDF2B924A7", 13 | GroupName = SystemTabNames.Content)] 14 | [SiteImageUrl] 15 | public class EditorialBlock : SiteBlockData 16 | { 17 | [Display(GroupName = SystemTabNames.Content)] 18 | [CultureSpecific] 19 | public virtual XhtmlString MainBody { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /AlloyReact/Models/Blocks/FormBlock.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using EPiServer.DataAbstraction; 3 | using EPiServer.DataAnnotations; 4 | using EPiServer.XForms; 5 | 6 | namespace AlloyReact.Models.Blocks 7 | { 8 | /// 9 | /// Used to insert an XForm 10 | /// 11 | [SiteContentType( 12 | GroupName = Global.GroupNames.Specialized, 13 | GUID = "FA326346-4D4C-4E82-AFE8-C36279006179")] 14 | [SiteImageUrl] 15 | public class FormBlock : 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 | [CultureSpecific] 27 | public virtual XForm Form { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /AlloyReact/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 AlloyReact.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 | -------------------------------------------------------------------------------- /AlloyReact/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 AlloyReact.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 | } 93 | -------------------------------------------------------------------------------- /AlloyReact/Models/Blocks/SiteBlockData.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace AlloyReact.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 | } 11 | -------------------------------------------------------------------------------- /AlloyReact/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 AlloyReact.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("/Static/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 | } 45 | -------------------------------------------------------------------------------- /AlloyReact/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 AlloyReact.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 | -------------------------------------------------------------------------------- /AlloyReact/Models/Blocks/ThreeKeyFactsBlock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using EPiServer.Core; 4 | using EPiServer.DataAbstraction; 5 | using EPiServer.DataAnnotations; 6 | using EPiServer.Web; 7 | 8 | namespace AlloyTemplates.Models.Blocks 9 | { 10 | [ContentType(DisplayName = "Three Key Facts", GUID = "ce581aa7-8c20-4084-bd2c-7e3e292fc314", Description = "Example of OPE overlays in react")] 11 | public class ThreeKeyFactsBlock : BlockData 12 | { 13 | [Required] 14 | [Display( 15 | Name = "First fact", 16 | Description = "", 17 | GroupName = SystemTabNames.Content, 18 | Order = 1)] 19 | [UIHint(UIHint.Textarea)] 20 | public virtual string FirstFact { get; set; } 21 | 22 | [Required] 23 | [Display( 24 | Name = "Second fact", 25 | Description = "", 26 | GroupName = SystemTabNames.Content, 27 | Order = 2)] 28 | [UIHint(UIHint.Textarea)] 29 | public virtual string SecondFact { get; set; } 30 | 31 | [Required] 32 | [Display( 33 | Name = "Third fact", 34 | Description = "", 35 | GroupName = SystemTabNames.Content, 36 | Order = 3)] 37 | [UIHint(UIHint.Textarea)] 38 | public virtual string ThirdFact { get; set; } 39 | 40 | [Required] 41 | [Display( 42 | Name = "Bonus content", 43 | Description = "Displayed when there are no more facts to display", 44 | GroupName = SystemTabNames.Content, 45 | Order = 4)] 46 | [UIHint(UIHint.Textarea)] 47 | public virtual string BonusContent { get; set; } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AlloyReact/Models/Media/GenericMedia.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Core; 2 | using EPiServer.DataAnnotations; 3 | using System; 4 | 5 | namespace AlloyReact.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 | } 16 | -------------------------------------------------------------------------------- /AlloyReact/Models/Media/ImageFile.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Core; 2 | using EPiServer.DataAnnotations; 3 | using EPiServer.Framework.DataAnnotations; 4 | using System.ComponentModel.DataAnnotations; 5 | 6 | namespace AlloyReact.Models.Media 7 | { 8 | [ContentType(GUID = "0A89E464-56D4-449F-AEA8-2BF774AB8730")] 9 | [MediaDescriptor(ExtensionString = "jpg,jpeg,jpe,ico,gif,bmp,png")] 10 | public class ImageFile : ImageData 11 | { 12 | /// 13 | /// Gets or sets the copyright. 14 | /// 15 | /// 16 | /// The copyright. 17 | /// 18 | public virtual string Copyright { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /AlloyReact/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 AlloyReact.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 | } 25 | -------------------------------------------------------------------------------- /AlloyReact/Models/Pages/ArticlePage.cs: -------------------------------------------------------------------------------- 1 | namespace AlloyReact.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 | -------------------------------------------------------------------------------- /AlloyReact/Models/Pages/ContactPage.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using AlloyReact.Business.Rendering; 3 | using EPiServer.Web; 4 | using EPiServer.Core; 5 | 6 | namespace AlloyReact.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 | -------------------------------------------------------------------------------- /AlloyReact/Models/Pages/ContainerPage.cs: -------------------------------------------------------------------------------- 1 | using AlloyReact.Business.Rendering; 2 | 3 | namespace AlloyReact.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 | } 17 | -------------------------------------------------------------------------------- /AlloyReact/Models/Pages/IHasRelatedContent.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Core; 2 | 3 | namespace AlloyReact.Models.Pages 4 | { 5 | public interface IHasRelatedContent 6 | { 7 | ContentArea RelatedContentArea { get; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /AlloyReact/Models/Pages/ISearchPage.cs: -------------------------------------------------------------------------------- 1 | namespace AlloyReact.Models.Pages 2 | { 3 | /// 4 | /// Marker interface for search implementation 5 | /// 6 | public interface ISearchPage 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /AlloyReact/Models/Pages/LandingPage.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using EPiServer.Core; 3 | using EPiServer.DataAbstraction; 4 | using EPiServer.DataAnnotations; 5 | 6 | namespace AlloyReact.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 | } 32 | -------------------------------------------------------------------------------- /AlloyReact/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 AlloyReact.Business; 7 | using AlloyReact.Models.Blocks; 8 | 9 | namespace AlloyReact.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 | } 37 | -------------------------------------------------------------------------------- /AlloyReact/Models/Pages/ProductPage.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using AlloyReact.Models.Blocks; 3 | using EPiServer.Core; 4 | using EPiServer.DataAbstraction; 5 | using EPiServer.DataAnnotations; 6 | using AlloyReact.Models.Properties; 7 | 8 | namespace AlloyReact.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 | [Required] 23 | [BackingType(typeof(PropertyStringList))] 24 | [Display(Order = 305)] 25 | [UIHint(Global.SiteUIHints.Strings)] 26 | [CultureSpecific] 27 | public virtual string[] UniqueSellingPoints { get; set; } 28 | 29 | [Display( 30 | GroupName = SystemTabNames.Content, 31 | Order = 330)] 32 | [CultureSpecific] 33 | [AllowedTypes(new[] { typeof(IContentData) },new[] { typeof(JumbotronBlock) })] 34 | public virtual ContentArea RelatedContentArea { get; set; } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /AlloyReact/Models/Pages/SearchPage.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using AlloyReact.Models.Blocks; 3 | using EPiServer.Core; 4 | using EPiServer.DataAbstraction; 5 | using EPiServer.DataAnnotations; 6 | 7 | namespace AlloyReact.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 | } 26 | -------------------------------------------------------------------------------- /AlloyReact/Models/Pages/SitePageData.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using EPiServer.Core; 3 | using EPiServer.DataAbstraction; 4 | using EPiServer.DataAnnotations; 5 | using AlloyReact.Business.Rendering; 6 | using AlloyReact.Models.Properties; 7 | using EPiServer.Web; 8 | 9 | namespace AlloyReact.Models.Pages 10 | { 11 | /// 12 | /// Base class for all page types 13 | /// 14 | public abstract class SitePageData : PageData, ICustomCssInContentArea 15 | { 16 | [Display( 17 | GroupName = Global.GroupNames.MetaData, 18 | Order = 100)] 19 | [CultureSpecific] 20 | public virtual string MetaTitle 21 | { 22 | get 23 | { 24 | var metaTitle = this.GetPropertyValue(p => p.MetaTitle); 25 | 26 | // Use explicitly set meta title, otherwise fall back to page name 27 | return !string.IsNullOrWhiteSpace(metaTitle) 28 | ? metaTitle 29 | : PageName; 30 | } 31 | set { this.SetPropertyValue(p => p.MetaTitle, value); } 32 | } 33 | 34 | [Display( 35 | GroupName = Global.GroupNames.MetaData, 36 | Order = 200)] 37 | [CultureSpecific] 38 | [BackingType(typeof(PropertyStringList))] 39 | public virtual string[] MetaKeywords { get; set; } 40 | 41 | [Display( 42 | GroupName = Global.GroupNames.MetaData, 43 | Order = 300)] 44 | [CultureSpecific] 45 | [UIHint(UIHint.Textarea)] 46 | public virtual string MetaDescription { get; set; } 47 | 48 | [Display( 49 | GroupName = Global.GroupNames.MetaData, 50 | Order = 400)] 51 | [CultureSpecific] 52 | public virtual bool DisableIndexing { get; set; } 53 | 54 | [Display( 55 | GroupName = SystemTabNames.Content, 56 | Order = 100)] 57 | [UIHint(UIHint.Image)] 58 | public virtual ContentReference PageImage { get; set; } 59 | 60 | [Display( 61 | GroupName = SystemTabNames.Content, 62 | Order = 200)] 63 | [CultureSpecific] 64 | [UIHint(UIHint.Textarea)] 65 | public virtual string TeaserText 66 | { 67 | get 68 | { 69 | var teaserText = this.GetPropertyValue(p => p.TeaserText); 70 | 71 | // Use explicitly set teaser text, otherwise fall back to description 72 | return !string.IsNullOrWhiteSpace(teaserText) 73 | ? teaserText 74 | : MetaDescription; 75 | } 76 | set { this.SetPropertyValue(p => p.TeaserText, value); } 77 | } 78 | 79 | [Display( 80 | GroupName = SystemTabNames.Settings, 81 | Order = 200)] 82 | [CultureSpecific] 83 | public virtual bool HideSiteHeader { get; set; } 84 | 85 | [Display( 86 | GroupName = SystemTabNames.Settings, 87 | Order = 300)] 88 | [CultureSpecific] 89 | public virtual bool HideSiteFooter { get; set; } 90 | 91 | public string ContentAreaCssClass 92 | { 93 | get { return "teaserblock"; } //Page partials should be style like teasers 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /AlloyReact/Models/Pages/StandardPage.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Core; 2 | using EPiServer.DataAbstraction; 3 | using EPiServer.DataAnnotations; 4 | using System.ComponentModel.DataAnnotations; 5 | 6 | namespace AlloyReact.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 | [UIHint("ReactNumber")] 27 | public virtual int SomeNumber { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /AlloyReact/Models/Pages/StartPage.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using EPiServer.Core; 3 | using EPiServer.DataAbstraction; 4 | using EPiServer.DataAnnotations; 5 | using EPiServer.SpecializedProperties; 6 | using AlloyReact.Models.Blocks; 7 | 8 | namespace AlloyReact.Models.Pages 9 | { 10 | /// 11 | /// Used for the site's start page and also acts as a container for site settings 12 | /// 13 | [ContentType( 14 | GUID = "19671657-B684-4D95-A61F-8DD4FE60D559", 15 | GroupName = Global.GroupNames.Specialized)] 16 | [SiteImageUrl] 17 | [AvailableContentTypes( 18 | Availability.Specific, 19 | Include = new[] { typeof(ContainerPage), typeof(ProductPage), typeof(StandardPage), typeof(ISearchPage), typeof(LandingPage), typeof(ContentFolder) }, // Pages we can create under the start page... 20 | ExcludeOn = new[] { typeof(ContainerPage), typeof(ProductPage), typeof(StandardPage), typeof(ISearchPage), typeof(LandingPage) })] // ...and underneath those we can't create additional start pages 21 | public class StartPage : SitePageData 22 | { 23 | [Display( 24 | GroupName = SystemTabNames.Content, 25 | Order = 320)] 26 | [CultureSpecific] 27 | public virtual ContentArea MainContentArea { get; set; } 28 | 29 | [Display(GroupName = Global.GroupNames.SiteSettings, Order = 300)] 30 | public virtual LinkItemCollection ProductPageLinks { get; set; } 31 | 32 | [Display(GroupName = Global.GroupNames.SiteSettings, Order = 350)] 33 | public virtual LinkItemCollection CompanyInformationPageLinks { get; set; } 34 | 35 | [Display(GroupName = Global.GroupNames.SiteSettings, Order = 400)] 36 | public virtual LinkItemCollection NewsPageLinks { get; set; } 37 | 38 | [Display(GroupName = Global.GroupNames.SiteSettings, Order = 450)] 39 | public virtual LinkItemCollection CustomerZonePageLinks { get; set; } 40 | 41 | [Display(GroupName = Global.GroupNames.SiteSettings)] 42 | public virtual PageReference GlobalNewsPageLink { get; set; } 43 | 44 | [Display(GroupName = Global.GroupNames.SiteSettings)] 45 | public virtual PageReference ContactsPageLink { get; set; } 46 | 47 | [Display(GroupName = Global.GroupNames.SiteSettings)] 48 | public virtual PageReference SearchPageLink { get; set; } 49 | 50 | [Display(GroupName = Global.GroupNames.SiteSettings)] 51 | public virtual SiteLogotypeBlock SiteLogotype { get; set; } 52 | 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /AlloyReact/Models/Properties/PropertyStringList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EPiServer.Core; 3 | using EPiServer.Framework.DataAnnotations; 4 | using EPiServer.PlugIn; 5 | 6 | namespace AlloyReact.Models.Properties 7 | { 8 | /// 9 | /// Property type for storing a list of strings 10 | /// 11 | /// For an example, see where this property type is used for the MetaKeywords property 12 | [EditorHint(Global.SiteUIHints.Strings)] 13 | [PropertyDefinitionTypePlugIn(Description = "A property for list of strings", DisplayName = "String List")] 14 | public class PropertyStringList : PropertyLongString 15 | { 16 | protected String Separator = "\n"; 17 | 18 | public String[] List 19 | { 20 | get 21 | { 22 | return (String[])Value; 23 | } 24 | } 25 | 26 | public override Type PropertyValueType 27 | { 28 | get 29 | { 30 | return typeof(String[]); 31 | } 32 | } 33 | 34 | public override object SaveData(PropertyDataCollection properties) 35 | { 36 | return LongString; 37 | } 38 | 39 | public override object Value 40 | { 41 | get 42 | { 43 | var value = base.Value as string; 44 | 45 | if (value == null) 46 | { 47 | return null; 48 | } 49 | 50 | return value.Split(Separator.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); 51 | } 52 | set 53 | { 54 | if (value is String[]) 55 | { 56 | var s = String.Join(Separator, value as String[]); 57 | base.Value = s; 58 | } 59 | else 60 | { 61 | base.Value = value; 62 | } 63 | 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /AlloyReact/Models/Register/RegisterViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.Web.Mvc; 3 | 4 | namespace AlloyReact.Models 5 | { 6 | public class RegisterViewModel 7 | { 8 | [Required] 9 | [Display(Name = "Username")] 10 | [RegularExpression(@"^[a-zA-Z0-9_-]+$", ErrorMessage = "Username can only contain letters a-z, numbers, underscores and hyphens.")] 11 | [StringLength(20, ErrorMessage ="The {0} field can not be more than {1} characters long.")] 12 | public string Username { get; set; } 13 | 14 | [Required] 15 | [EmailAddress] 16 | [Display(Name = "Email")] 17 | public string Email { get; set; } 18 | 19 | [Required] 20 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 21 | [DataType(DataType.Password)] 22 | [Display(Name = "Password")] 23 | [AllowHtml] 24 | public string Password { get; set; } 25 | 26 | [DataType(DataType.Password)] 27 | [Display(Name = "Confirm password")] 28 | [System.ComponentModel.DataAnnotations.Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] 29 | [AllowHtml] 30 | public string ConfirmPassword { get; set; } 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AlloyReact/Models/SiteContentType.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.DataAnnotations; 2 | 3 | namespace AlloyReact.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 | } 16 | -------------------------------------------------------------------------------- /AlloyReact/Models/SiteImageUrl.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.DataAnnotations; 2 | 3 | namespace AlloyReact.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("~/Static/gfx/page-type-thumbnail.png") 14 | { 15 | 16 | } 17 | 18 | public SiteImageUrl(string path) : base(path) 19 | { 20 | 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AlloyReact/Models/ViewModels/ContactBlockModel.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.ComponentModel.DataAnnotations; 3 | using AlloyReact.Models.Pages; 4 | using EPiServer.Web; 5 | using EPiServer.Core; 6 | 7 | namespace AlloyReact.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 IHtmlString LinkUrl { get; set; } 16 | public bool ShowLink { get; set; } 17 | public ContactPage ContactPage { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AlloyReact/Models/ViewModels/ContentRenderingErrorModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EPiServer; 3 | using EPiServer.Core; 4 | 5 | namespace AlloyReact.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 | } 31 | -------------------------------------------------------------------------------- /AlloyReact/Models/ViewModels/IPageViewModel.cs: -------------------------------------------------------------------------------- 1 | using EPiServer.Core; 2 | using AlloyReact.Models.Pages; 3 | 4 | namespace AlloyReact.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 | } 20 | -------------------------------------------------------------------------------- /AlloyReact/Models/ViewModels/ImageViewModel.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace AlloyReact.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 | } 25 | -------------------------------------------------------------------------------- /AlloyReact/Models/ViewModels/LayoutModel.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Mvc; 3 | using EPiServer.SpecializedProperties; 4 | using AlloyReact.Models.Blocks; 5 | 6 | namespace AlloyReact.Models.ViewModels 7 | { 8 | public class LayoutModel 9 | { 10 | public SiteLogotypeBlock Logotype { get; set; } 11 | public IHtmlString LogotypeLinkUrl { get; set; } 12 | public bool HideHeader { get; set; } 13 | public bool HideFooter { get; set; } 14 | public LinkItemCollection ProductPages { get; set; } 15 | public LinkItemCollection CompanyInformationPages { get; set; } 16 | public LinkItemCollection NewsPages { get; set; } 17 | public LinkItemCollection CustomerZonePages { get; set; } 18 | public bool LoggedIn { get; set; } 19 | public MvcHtmlString LoginUrl { get; set; } 20 | public MvcHtmlString LogOutUrl { get; set; } 21 | public MvcHtmlString SearchActionUrl { get; set; } 22 | 23 | public bool IsInReadonlyMode {get;set;} 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /AlloyReact/Models/ViewModels/PageListModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using AlloyReact.Business; 4 | using AlloyReact.Controllers; 5 | using AlloyReact.Helpers; 6 | using EPiServer.Core; 7 | using AlloyReact.Models.Blocks; 8 | using AlloyReact.Models.Pages; 9 | using EPiServer; 10 | using EPiServer.ServiceLocation; 11 | using EPiServer.Web.Routing; 12 | 13 | namespace AlloyReact.Models.ViewModels 14 | { 15 | public class PageListModel 16 | { 17 | private Injected _contentLocator; 18 | private Injected _contentLoader; 19 | 20 | private List _pages = new List(); 21 | 22 | public PageListModel(PageListBlock block) 23 | { 24 | Heading = block.Heading; 25 | IncludeIntroduction = block.IncludeIntroduction; 26 | IncludePublishDate = block.IncludePublishDate; 27 | 28 | // Content link is either for an independent block, or for content with a property of type PageListBlock 29 | ContentLink = block is IContent ? ((IContent)block).ContentLink : ServiceLocator.Current.GetInstance().ContentLink; 30 | 31 | Pages = new PageListBlockController(_contentLocator.Service, _contentLoader.Service).FindPages(block); 32 | } 33 | 34 | public string Heading { get; set; } 35 | 36 | public IEnumerable Pages 37 | { 38 | get { return _pages.Select(p => new { name = p.Name, description = (p as SitePageData)?.TeaserText, date = p.StartPublish?.ToShortDateString(), cssClass = p.GetThemeCssClassNames(), url = UrlResolver.Current.GetUrl(p) }); } 39 | set { _pages = ((IEnumerable) value).ToList(); } 40 | } 41 | 42 | public bool IncludeIntroduction { get; set; } 43 | 44 | public bool IncludePublishDate { get; set; } 45 | 46 | public ContentReference ContentLink { get; protected set; } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /AlloyReact/Models/ViewModels/PageViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EPiServer.Core; 3 | using AlloyReact.Models.Pages; 4 | 5 | namespace AlloyReact.Models.ViewModels 6 | { 7 | public class PageViewModel : IPageViewModel where T : SitePageData 8 | { 9 | public PageViewModel(T currentPage) 10 | { 11 | CurrentPage = currentPage; 12 | } 13 | 14 | public T CurrentPage { get; private set; } 15 | public LayoutModel Layout { get; set; } 16 | public IContent Section { get; set; } 17 | } 18 | 19 | public static class PageViewModel 20 | { 21 | /// 22 | /// Returns a PageViewModel of type . 23 | /// 24 | /// 25 | /// Convenience method for creating PageViewModels without having to specify the type as methods can use type inference while constructors cannot. 26 | /// 27 | public static PageViewModel Create(T page) where T : SitePageData 28 | { 29 | return new PageViewModel(page); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /AlloyReact/Models/ViewModels/PreviewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EPiServer.Core; 3 | using AlloyReact.Models.Pages; 4 | 5 | namespace AlloyReact.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 | } 28 | -------------------------------------------------------------------------------- /AlloyReact/Models/ViewModels/SearchContentModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using AlloyReact.Models.Pages; 3 | 4 | namespace AlloyReact.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 | -------------------------------------------------------------------------------- /AlloyReact/Models/ViewModels/VideoViewModel.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace AlloyReact.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 | } 20 | -------------------------------------------------------------------------------- /AlloyReact/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("AlloyReact")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("AlloyReact")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("32a0f2d9-e0f2-4680-b74d-51aca331e515")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /AlloyReact/Resources/LanguageFiles/Display.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Mobile 7 | 8 | 9 | Web 10 | 11 | 12 | 13 | Full 14 | Wide 15 | Narrow 16 | 17 | 18 | Standard (1366x768) 19 | iPad horizontal (1024x768) 20 | iPhone vertical (320x568) 21 | Android vertical (480x800) 22 | 23 | 24 | -------------------------------------------------------------------------------- /AlloyReact/Resources/LanguageFiles/EditorHints.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Button Text 11 | 12 | 13 | 14 | 15 | 16 | This block type does not have a renderer for this type of content area. 17 | 18 | 19 | 20 | 21 | 22 | Error while rendering {0} {1} 23 | 24 | 25 | 26 | The block '{0}' when displayed as {1} 27 | The block '{0}' cannot be displayed as {1} 28 | No renderer found for '{0}' 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /AlloyReact/Resources/LanguageFiles/GroupNames.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | Default 9 | 10 | 11 | News 12 | 13 | 14 | Products 15 | 16 | 17 | SEO 18 | 19 | 20 | Site settings 21 | 22 | 23 | Specialized 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /AlloyReact/Resources/LanguageFiles/Views.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | E-mail 8 | Phone 9 | No contact selected 10 | 11 | 12 |
13 | The Company 14 | Customer Zone 15 | Log in 16 | Log out 17 | News & Events 18 | Products 19 |
20 | 21 | 22 | Search 23 | 24 | 25 | 26 | Latest news 27 | News list will be empty since no list root has been set 28 | 29 | 30 | 31 | no 32 | Search result 33 | Search 34 | Your search for 35 | resulted in 36 | hits 37 | EPiServer Search is not configured or is not active for this website. 38 | 39 | 40 |
41 | Thank you for your post! 42 |
43 | 44 |
45 | 46 |
47 | -------------------------------------------------------------------------------- /AlloyReact/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 | -------------------------------------------------------------------------------- /AlloyReact/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web; 3 | using EPiServer.Cms.UI.AspNetIdentity; 4 | using Microsoft.AspNet.Identity; 5 | using Microsoft.AspNet.Identity.Owin; 6 | using Microsoft.Owin; 7 | using Microsoft.Owin.Security.Cookies; 8 | using Owin; 9 | 10 | [assembly: OwinStartup(typeof(AlloyReact.Startup))] 11 | 12 | namespace AlloyReact 13 | { 14 | public class Startup 15 | { 16 | 17 | public void Configuration(IAppBuilder app) 18 | { 19 | 20 | // Add CMS integration for ASP.NET Identity 21 | app.AddCmsAspNetIdentity(); 22 | 23 | // Remove to block registration of administrators 24 | app.UseAdministratorRegistrationPage(() => HttpContext.Current.Request.IsLocal); 25 | 26 | // Use cookie authentication 27 | app.UseCookieAuthentication(new CookieAuthenticationOptions 28 | { 29 | AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 30 | LoginPath = new PathString(Global.LoginPath), 31 | Provider = new CookieAuthenticationProvider 32 | { 33 | // If the "/util/login.aspx" has been used for login otherwise you don't need it you can remove OnApplyRedirect. 34 | OnApplyRedirect = cookieApplyRedirectContext => 35 | { 36 | app.CmsOnCookieApplyRedirect(cookieApplyRedirectContext, cookieApplyRedirectContext.OwinContext.Get>()); 37 | }, 38 | 39 | // Enables the application to validate the security stamp when the user logs in. 40 | // This is a security feature which is used when you change a password or add an external login to your account. 41 | OnValidateIdentity = SecurityStampValidator.OnValidateIdentity, ApplicationUser>( 42 | validateInterval: TimeSpan.FromMinutes(30), 43 | regenerateIdentity: (manager, user) => manager.GenerateUserIdentityAsync(user)) 44 | } 45 | }); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /AlloyReact/Static/css/editmode.css: -------------------------------------------------------------------------------- 1 | /* CSS specific to edit mode, such as help content displayed to the editor */ 2 | 3 | .alert-info 4 | { 5 | border-color: #B8C0C5; 6 | color: black; 7 | font-family: Verdana; 8 | font-size: 1em; 9 | font-style: italic; 10 | background-color: #B8C0C5; 11 | box-shadow: 3px 3px 5px #CCC; 12 | text-align: center; 13 | } 14 | 15 | .alert-error p { 16 | text-align: left; 17 | } 18 | 19 | .alert-error .heading { 20 | font-weight: bold; 21 | color: #ff0000; 22 | } 23 | 24 | .alert-error .details { 25 | font-size: 0.8em; 26 | max-height: 100px; 27 | overflow: scroll; 28 | } 29 | 30 | .header.dim { 31 | margin: 2% 0; 32 | opacity: 0.3; 33 | } -------------------------------------------------------------------------------- /AlloyReact/Static/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 | } -------------------------------------------------------------------------------- /AlloyReact/Static/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 | -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/New_FDT_Press_Contact_.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/New_FDT_Press_Contact_.JPG -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/carouselbackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/carouselbackground.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/contact.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/contact.jpg -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/exampelspan4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/exampelspan4.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/experts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/experts.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/fallows-media-wide.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/fallows-media-wide.jpg -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/leader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/leader.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/leader2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/leader2.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/logotype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/logotype.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/meet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/meet.jpg -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/page-type-thumbnail-article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/page-type-thumbnail-article.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/page-type-thumbnail-contact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/page-type-thumbnail-contact.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/page-type-thumbnail-product.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/page-type-thumbnail-product.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/page-type-thumbnail-standard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/page-type-thumbnail-standard.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/page-type-thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/page-type-thumbnail.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/person.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/person.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/plan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/plan.jpg -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/play.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/playInactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/playInactive.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/productLandingv2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/productLandingv2.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/searchbutton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/searchbutton.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/searchbuttonsmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/searchbuttonsmall.png -------------------------------------------------------------------------------- /AlloyReact/Static/gfx/track.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/gfx/track.jpg -------------------------------------------------------------------------------- /AlloyReact/Static/html/error.htm: -------------------------------------------------------------------------------- 1 |  2 | 3 | An error occured 4 | 5 | 6 | 9 | Logotype 10 |

When things go wrong...

11 |

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

12 | 13 | 14 | -------------------------------------------------------------------------------- /AlloyReact/Static/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /AlloyReact/Static/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /AlloyReact/Static/jwplayer/player.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/jwplayer/player.swf -------------------------------------------------------------------------------- /AlloyReact/Static/jwplayer/preview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/jwplayer/preview.jpg -------------------------------------------------------------------------------- /AlloyReact/Static/jwplayer/video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/Static/jwplayer/video.mp4 -------------------------------------------------------------------------------- /AlloyReact/Static/react/Clock.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default class Clock extends React.Component { 4 | 5 | constructor(props) { 6 | super(props); 7 | 8 | this.state = { 9 | time: this.getTimeString() 10 | }; 11 | 12 | this.timerHandle = setInterval(this.refreshTime.bind(this), 1000); 13 | } 14 | 15 | getTimeString() { 16 | var date = new Date(), 17 | hours = date.getHours().toString(), 18 | minutes = date.getMinutes().toString(), 19 | seconds = date.getSeconds().toString(); 20 | 21 | return hours + ":" + (minutes.length === 1 ? ("0" + minutes) : minutes) + ":" + (seconds.length === 1 ? ("0" + seconds) : seconds); 22 | } 23 | 24 | refreshTime() { 25 | 26 | this.setState({ 27 | time: this.getTimeString() 28 | }); 29 | } 30 | 31 | componentWillUnmount() { 32 | clearInterval(this.timerHandle); 33 | } 34 | 35 | render() { 36 | return {this.state.time}; 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /AlloyReact/Static/react/ReactNumber.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Clock from "./Clock"; 3 | 4 | export default class ReactBlock extends React.Component { 5 | 6 | constructor(props) { 7 | super(props); 8 | 9 | this.state = { 10 | number: props.someNumber, 11 | firstRender: new Date() 12 | }; 13 | } 14 | 15 | render() { 16 | return ( 17 |
18 | This React component was rendered at {this.state.firstRender.toLocaleTimeString("sv-SE")} with a number of {this.props.someNumber}.

19 | The current value of the {this.props.propertyName} property is {this.state.number}, and the current time is: 20 |
21 | ); 22 | } 23 | 24 | componentDidMount() { 25 | 26 | if (document.getElementsByTagName("HTML")[0].dataset.editMode === 'True') { // We are in edit mode 27 | 28 | window.addEventListener('load', function () { // Ensure the 'epi' object has been initialized 29 | 30 | var epi = window.epi; 31 | 32 | epi.subscribe("beta/contentSaved", function (propertyDetails) { 33 | 34 | // Check if it was "our" property that changed 35 | if (this.props.propertyName.toUpperCase() === propertyDetails.properties[0].name.toUpperCase()) { 36 | this.setState({ number: propertyDetails.properties[0].value }); // Update this component's state to reflect the new property value in the UI 37 | } 38 | }.bind(this)); 39 | 40 | 41 | }.bind(this)); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /AlloyReact/Static/react/ThreeKeyFacts.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default class ThreeKeyFacts extends React.Component { 4 | 5 | constructor(props) { 6 | super(props); 7 | 8 | this.state = { 9 | currentIndex: 0, 10 | facts: this.props.facts, 11 | bonusContent: this.props.bonusContent 12 | }; 13 | 14 | this.next = this.next.bind(this); 15 | this.previous = this.previous.bind(this); 16 | } 17 | 18 | render() { 19 | 20 | let bonusContentToDisplay = null; 21 | 22 | if (this.state.currentIndex === this.state.facts.length - 1) { 23 | bonusContentToDisplay =

{this.state.bonusContent}

; 24 | 25 | console.log(`Reached fact ${this.state.currentIndex + 1}, bonus content will be displayed`, bonusContentToDisplay); 26 | } 27 | 28 | return( 29 |
30 |

Fact #{this.state.currentIndex + 1}

31 |

{this.state.facts[this.state.currentIndex].fact}

32 | 33 | {bonusContentToDisplay} 34 |
35 | ); 36 | } 37 | 38 | next() { 39 | this.setState({ 40 | currentIndex: this.state.currentIndex + 1 41 | }); 42 | } 43 | 44 | previous() { 45 | this.setState({ 46 | currentIndex: this.state.currentIndex - 1 47 | }); 48 | } 49 | 50 | componentDidMount() { 51 | 52 | window.addEventListener('load', function () { 53 | 54 | if (window.epi && window.epi.subscribe) { 55 | window.epi.subscribe("beta/contentSaved", function (propertyDetails) { 56 | 57 | if (!propertyDetails.successful) { 58 | return; 59 | } 60 | 61 | for (let i = 0; i < propertyDetails.properties.length; i++) { 62 | 63 | const savedProperty = propertyDetails.properties[i]; 64 | 65 | for (let j = 0; j < this.props.facts.length; j++) { 66 | 67 | // Fact updated 68 | if (savedProperty.name.toUpperCase() === this.props.facts[j].propertyName.toUpperCase()) { 69 | 70 | var factsCopy = this.state.facts; 71 | 72 | factsCopy[j].fact = savedProperty.value; 73 | 74 | this.setState({ 75 | facts: factsCopy 76 | }); 77 | } 78 | } 79 | 80 | // Bonus content updated 81 | if (savedProperty.name === "bonusContent") { 82 | this.setState({ 83 | bonusContent: savedProperty.value 84 | }); 85 | } 86 | } 87 | }.bind(this)); 88 | } 89 | }.bind(this)); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /AlloyReact/Static/react/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import ReactNumber from "./ReactNumber"; 4 | import PageListBlock from "./PageListBlock"; 5 | import ThreeKeyFacts from "./ThreeKeyFacts"; 6 | 7 | // Dictionary of available component types to be able to get a class from its literal name 8 | const ComponentTypes = { 9 | "PageListBlock": PageListBlock, 10 | "ReactNumber": ReactNumber, 11 | "ThreeKeyFacts": ThreeKeyFacts 12 | } 13 | 14 | document.addEventListener("DOMContentLoaded", function (event) { 15 | 16 | /** Mounts a React component based on container element attributes */ 17 | function initialize(componentContainer) { 18 | 19 | // Pass initial state from attribute on component container element 20 | var props = JSON.parse(componentContainer.dataset.props || "{}"); 21 | 22 | props.propertyName = componentContainer.dataset.epiPropertyName; 23 | 24 | // Render the component by resolving its class based on name 25 | ReactDOM.render( 26 | React.createElement( 27 | ComponentTypes[componentContainer.dataset.reactComponent], props 28 | ), componentContainer); 29 | } 30 | 31 | var reactComponents = document.querySelectorAll("[data-react-component]"); 32 | 33 | // If the user is using IE 11 or lower we need to convert the nodeList to a regular array 34 | reactComponents = Array.prototype.slice.call(reactComponents); 35 | 36 | // Mount React components 37 | reactComponents.forEach(initialize); 38 | }); -------------------------------------------------------------------------------- /AlloyReact/Views/ArticlePage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using AlloyReact 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 | -------------------------------------------------------------------------------- /AlloyReact/Views/ContactBlock/Index.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 |
14 | -------------------------------------------------------------------------------- /AlloyReact/Views/ImageFile/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model ImageViewModel 2 | 3 | @Model.Name 4 | -------------------------------------------------------------------------------- /AlloyReact/Views/LandingPage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using AlloyReact 2 | @model PageViewModel 3 |
4 | @Html.PropertyFor(x => x.CurrentPage.MainContentArea, new { CssClass = "row equal-height", tag = Global.ContentAreaTags.FullWidth }) 5 |
6 | -------------------------------------------------------------------------------- /AlloyReact/Views/NewsPage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using AlloyReact 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.DisplayFor(x => x.CurrentPage.NewsList) 14 | @Html.PropertyFor(x => x.CurrentPage.MainContentArea, new { CssClass = "row", Tag = Global.ContentAreaTags.TwoThirdsWidth }) -------------------------------------------------------------------------------- /AlloyReact/Views/PageListBlock/Index.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 | } 24 | -------------------------------------------------------------------------------- /AlloyReact/Views/Preview/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model PreviewModel 2 | 3 | @foreach(var area in Model.Areas) 4 | { 5 | if(area.Supported) 6 | { 7 | @Html.Partial("TemplateHint", string.Format(@Html.Translate("/preview/heading"), Model.PreviewContent.Name, @Html.Translate(area.AreaName))) 8 |
9 | @Html.DisplayFor(x => area.ContentArea, new {Tag = area.AreaTag}) 10 |
11 | } 12 | else 13 | { 14 | @Html.Partial("TemplateHint", string.Format(@Html.Translate("/preview/norenderer"), Model.PreviewContent.Name, @Html.Translate(area.AreaName))) 15 | } 16 | } 17 | 18 | @if(!Model.Areas.Any()) 19 | { 20 | @Html.Partial("TemplateHint", string.Format(@Html.Translate("/preview/norendereratall"), Model.PreviewContent.Name)) 21 | } 22 | -------------------------------------------------------------------------------- /AlloyReact/Views/ProductPage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using AlloyReact 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 | @Html.PropertyFor(x => x.CurrentPage.UniqueSellingPoints) 24 |
25 | 26 | @Html.PropertyFor(x => x.CurrentPage.RelatedContentArea, new { CssClass = "row", Tag = Global.ContentAreaTags.OneThirdWidth }) 27 | } 28 | -------------------------------------------------------------------------------- /AlloyReact/Views/Register/Index.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | @using System.Web.Optimization 4 | @using AlloyReact.Controllers 5 | @model AlloyReact.Models.RegisterViewModel 6 | @{ 7 | Layout = ""; 8 | } 9 | 10 | 11 | 12 | Create Administrator Account 13 | @Styles.Render("~/bundles/css") 14 | @Scripts.Render("~/bundles/js") 15 | 16 | 17 | 18 |
19 |
20 |
21 | 22 |

Create Administrator Account

23 | 24 | @using (Html.BeginForm("/", "Register", FormMethod.Post)) 25 | { 26 | @Html.AntiForgeryToken() 27 |
28 | @Html.LabelFor(m => m.Username) 29 | @Html.TextBoxFor(m => m.Username) 30 | @Html.ValidationMessageFor(m => m.Username) 31 |
32 |
33 | @Html.LabelFor(m => m.Email) 34 | @Html.TextBoxFor(m => m.Email) 35 | @Html.ValidationMessageFor(m => m.Email) 36 |
37 |
38 | @Html.LabelFor(m => m.Password) 39 | @Html.PasswordFor(m => m.Password) 40 | @Html.ValidationMessageFor(m => m.Password) 41 |
42 |
43 | @Html.LabelFor(m => m.ConfirmPassword) 44 | @Html.PasswordFor(m => m.ConfirmPassword) 45 | @Html.ValidationMessageFor(m => m.ConfirmPassword) 46 |
47 |
48 | @Html.ValidationMessage(RegisterController.ErrorKey) 49 |
50 |
51 | 52 |
53 | } 54 |
55 |
56 |
57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /AlloyReact/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, PageEditing.PageIsInEditMode ? 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 && PrincipalInfo.HasEditAccess) 61 | { 62 | @Html.Partial("TemplateHint", Html.Translate("/searchpagetemplate/disabled" )) 63 | } 64 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/Blocks/ButtonBlock.cshtml: -------------------------------------------------------------------------------- 1 | @model ButtonBlock 2 | 3 | m.ButtonText)> 4 | @{ 5 | var buttonText = string.IsNullOrWhiteSpace(Model.ButtonText) 6 | ? Html.Translate("/blocks/buttonblockcontrol/buttondefaulttext") 7 | : Model.ButtonText; 8 | } 9 | @buttonText 10 | 11 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/Blocks/EditorialBlock.cshtml: -------------------------------------------------------------------------------- 1 | @model EditorialBlock 2 | 3 |
x.MainBody)> 4 | @Html.DisplayFor(x => Model.MainBody) 5 |
6 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/Blocks/FormBlock.cshtml: -------------------------------------------------------------------------------- 1 | @model FormBlock 2 | 3 |

m.Heading)>@Model.Heading

4 | @Html.PropertyFor(x => x.Form) 5 | -------------------------------------------------------------------------------- /AlloyReact/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 |
14 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/Blocks/NoRenderer.cshtml: -------------------------------------------------------------------------------- 1 | @using EPiServer.Shell.Web.Mvc.Html 2 | @Html.Partial("TemplateHint", @Html.Translate("/blocks/norenderer/message")) 3 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/Blocks/SiteLogotypeBlock.cshtml: -------------------------------------------------------------------------------- 1 | @model SiteLogotypeBlock 2 | 3 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/Blocks/TeaserBlock.cshtml: -------------------------------------------------------------------------------- 1 | @using EPiServer.Core 2 | @using AlloyReact.Controllers 3 | @model TeaserBlock 4 |
5 | @*Link the teaser block only if a link has been set and not displayed in preview*@ 6 | @using(Html.BeginConditionalLink( 7 | !ContentReference.IsNullOrEmpty(Model.Link) && !(ViewContext.Controller is PreviewController), 8 | Url.PageLinkUrl(Model.Link), 9 | Model.Heading)) 10 | { 11 |

x.Heading)>@Model.Heading

12 |

x.Text)>@Model.Text

13 |
x.Image)>
14 | } 15 | 16 |
17 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/Blocks/TeaserBlockWide.cshtml: -------------------------------------------------------------------------------- 1 | @using EPiServer.Core 2 | @using AlloyReact.Controllers 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) && !(ViewContext.Controller is PreviewController), 9 | Url.PageLinkUrl(Model.Link), 10 | Model.Heading)) 11 | { 12 |
13 |
x.Image)> 14 | 15 |
16 |
17 |

x.Heading)>@Model.Heading

18 |

x.Text)>@Model.Text

19 |
20 |
21 | } 22 |
23 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/Blocks/ThreeKeyFactsBlock.cshtml: -------------------------------------------------------------------------------- 1 | @using AlloyTemplates.Models.Blocks 2 | @model ThreeKeyFactsBlock 3 | 4 | @Html.ReactComponent( 5 | "ThreeKeyFacts", /* The React component to mount */ 6 | new /* Object to pass as props to the React component */ 7 | { 8 | facts = new[] 9 | { 10 | new { propertyName = "FirstFact", fact = Model.FirstFact }, 11 | new { propertyName = "SecondFact", fact = Model.SecondFact }, 12 | new { propertyName = "ThirdFact", fact = Model.ThirdFact } 13 | }, 14 | bonusContent = Model.BonusContent 15 | }) 16 | -------------------------------------------------------------------------------- /AlloyReact/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 | @helper ItemTemplate(HtmlHelpers.MenuItem breadCrumbItem) { 5 | if (breadCrumbItem.Selected) 6 | { 7 | if (breadCrumbItem.Page.HasTemplate() && !breadCrumbItem.Page.ContentLink.CompareToIgnoreWorkID(Model.CurrentPage.ContentLink)) 8 | { 9 | @Html.PageLink(breadCrumbItem.Page) 10 | } 11 | else 12 | { 13 | @breadCrumbItem.Page.PageName 14 | } 15 | if (!breadCrumbItem.Page.ContentLink.CompareToIgnoreWorkID(Model.CurrentPage.ContentLink)) 16 | { 17 | / 18 | @Html.MenuList(breadCrumbItem.Page.ContentLink, ItemTemplate) 19 | } 20 | } 21 | } 22 | 23 |
24 |
25 |
    26 | @Html.ContentLink(SiteDefinition.Current.StartPage) 27 | / 28 | @Html.MenuList(SiteDefinition.Current.StartPage, ItemTemplate, requireVisibleInMenu: false, requirePageTemplate: false) 29 |
30 |
31 |
32 | -------------------------------------------------------------------------------- /AlloyReact/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 |

15 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/DisplayTemplates/DateTime.cshtml: -------------------------------------------------------------------------------- 1 | @model DateTime 2 | @Model.ToString("d MMMM yyyy") 3 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/DisplayTemplates/Image.cshtml: -------------------------------------------------------------------------------- 1 | @model EPiServer.Core.ContentReference 2 | @if (Model != null) 3 | { 4 | 5 | } -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/DisplayTemplates/PageListBlock.cshtml: -------------------------------------------------------------------------------- 1 | @model PageListBlock 2 | 3 | @Html.ReactComponentFor(ViewData.ModelMetadata.PropertyName, "PageListBlock", new PageListModel(Model)) -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/DisplayTemplates/ReactNumber.cshtml: -------------------------------------------------------------------------------- 1 | @model int 2 | 3 | @Html.ReactComponentFor( 4 | ViewData.ModelMetadata.PropertyName, /* Name of the property rendered */ 5 | "ReactNumber", /* The React component to mount */ 6 | new { someNumber = Model } /* Object to pass as props to the React component */) 7 | 8 | @* 9 | The ReactComponentFor helper basically renders the markup below, 10 | but also requires a script resource (our Webpack bundle) defined in module.config: 11 | 12 |
16 | *@ -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/DisplayTemplates/StringList.cshtml: -------------------------------------------------------------------------------- 1 | @model string[] 2 | @if(Model != null && Model.Length > 0) 3 | { 4 |
    5 | @foreach(var stringValue in Model) 6 | { 7 |
  • @stringValue
  • 8 | } 9 |
10 | } 11 | 12 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/Footer.cshtml: -------------------------------------------------------------------------------- 1 | @model IPageViewModel 2 |
3 | 40 |
41 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/Header.cshtml: -------------------------------------------------------------------------------- 1 | @using EPiServer.Editor 2 | @using EPiServer.Core 3 | @using EPiServer.Web 4 | @model IPageViewModel 5 |
6 | 51 |
52 | 53 |
54 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/Layouts/_LeftNavigation.cshtml: -------------------------------------------------------------------------------- 1 | @model IPageViewModel 2 | 3 | @{ Layout = "~/Views/Shared/Layouts/_Root.cshtml"; } 4 | 5 | @{Html.RenderPartial("Breadcrumbs", Model);} 6 | 7 |
8 |
9 |
10 |
11 | @{Html.RenderPartial("SubNavigation", Model);} 12 | @RenderSection("RelatedContent", false) 13 |
14 |
15 |
16 | 17 |
18 | @RenderBody() 19 |
20 |
21 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/Layouts/_Root.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Web.Optimization 2 | @using EPiServer.Framework.Web.Mvc.Html 3 | @using EPiServer.Editor 4 | @model IPageViewModel 5 | 6 | 7 | 8 | 9 | 10 | 11 | @Model.CurrentPage.MetaTitle 12 | 13 | @Html.CanonicalLink() 14 | @Html.AlternateLinks() 15 | @Styles.Render("~/bundles/css") 16 | @Scripts.Render("~/bundles/js") 17 | @Html.RequiredClientResources("Header") @*Enable components to require resources. For an example, see the view for VideoBlock.*@ 18 | 19 | 20 | 21 | @if (Model.Layout.IsInReadonlyMode) 22 | { 23 | Html.RenderPartial("Readonly", Model); 24 | } 25 | 26 | @Html.RenderEPiServerQuickNavigator() 27 | @Html.FullRefreshPropertiesMetaData() 28 |
29 | @if(!Model.Layout.HideHeader) 30 | { 31 | Html.RenderPartial("Header", Model); 32 | } 33 | @RenderBody() 34 | @if(!Model.Layout.HideFooter) 35 | { 36 | Html.RenderPartial("Footer", Model); 37 | } 38 |
39 | @Html.RequiredClientResources("Footer") 40 | 41 | 42 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/Layouts/_TwoPlusOne.cshtml: -------------------------------------------------------------------------------- 1 | @using AlloyReact 2 | @model IPageViewModel 3 | @{ Layout = "~/Views/Shared/Layouts/_Root.cshtml"; } 4 | 5 | @{Html.RenderPartial("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 | -------------------------------------------------------------------------------- /AlloyReact/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 |
12 | -------------------------------------------------------------------------------- /AlloyReact/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 |
15 | -------------------------------------------------------------------------------- /AlloyReact/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 |
12 | -------------------------------------------------------------------------------- /AlloyReact/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 |
15 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/Readonly.cshtml: -------------------------------------------------------------------------------- 1 | @model IPageViewModel 2 | 3 |
4 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/SubNavigation.cshtml: -------------------------------------------------------------------------------- 1 | @model IPageViewModel 2 | 3 | @helper ItemTemplate(HtmlHelpers.MenuItem firstLevelItem) { 4 | 10 |
11 |
    12 | @Html.MenuList(firstLevelItem.Page.ContentLink, SubLevelItemTemplate) 13 |
14 |
15 | } 16 | 17 | @helper SubLevelItemTemplate(HtmlHelpers.MenuItem subLevelItem) { 18 |
  • 19 | @Html.PageLink(subLevelItem.Page) 20 | @*To show more levels call Html.MenuList recursively here if subLevelItem.Selected == true*@ 21 |
  • 22 | } 23 | 24 |
    25 |
    26 | @if(Model.Section != null) { 27 | @Html.MenuList(Model.Section.ContentLink, ItemTemplate) 28 | } 29 |
    30 |
    31 | -------------------------------------------------------------------------------- /AlloyReact/Views/Shared/TemplateError.cshtml: -------------------------------------------------------------------------------- 1 | @model ContentRenderingErrorModel 2 |
    3 |

    @string.Format(Html.Translate("/renderingerror/heading"), Model.ContentTypeName, Model.ContentName)

    4 |

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

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

    @Model

    3 | -------------------------------------------------------------------------------- /AlloyReact/Views/StandardPage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using AlloyReact 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 | 15 | @Html.DisplayFor(x => x.CurrentPage.SomeNumber) 16 | -------------------------------------------------------------------------------- /AlloyReact/Views/StartPage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using AlloyReact 2 | @model PageViewModel 3 | 4 | @Html.PropertyFor(x => x.CurrentPage.MainContentArea, new { CssClass = "row equal-height", tag = Global.ContentAreaTags.FullWidth }) 5 | -------------------------------------------------------------------------------- /AlloyReact/Views/VideoFile/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using EPiServer.Framework.Web.Resources 2 | @model VideoViewModel 3 | @{ 4 | ClientResources.RequireScript(Href("~/static/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 | -------------------------------------------------------------------------------- /AlloyReact/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 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /AlloyReact/Views/_viewstart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/Layouts/_Root.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /AlloyReact/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /AlloyReact/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /AlloyReact/favicon.ico: -------------------------------------------------------------------------------- 1 | h( ...>>>Ɋ9777000$$$666!!!### -------------------------------------------------------------------------------- /AlloyReact/gulpfile.js: -------------------------------------------------------------------------------- 1 | /// 2 | //"use strict"; 3 | 4 | const gulp = require("gulp"), 5 | util = require("gulp-util"), 6 | webpack = require("webpack"), 7 | webpackConfig = require("./webpack.config");; 8 | 9 | gulp.task('webpack', function (callback) { 10 | var config = Object.create(webpackConfig); 11 | 12 | config.plugins = [ 13 | new webpack.optimize.UglifyJsPlugin({ sourceMap: true }) 14 | ]; 15 | 16 | webpack(config, function (err, stats) { 17 | if (err) { 18 | throw new util.PluginError('webpack', err) 19 | } 20 | 21 | util.log('[webpack]', stats.toString({ 22 | colors: true, 23 | progress: true, 24 | errorDetails: true 25 | })); 26 | }); 27 | }); -------------------------------------------------------------------------------- /AlloyReact/module.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /AlloyReact/modules/_protected/CMS/CMS.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/modules/_protected/CMS/CMS.zip -------------------------------------------------------------------------------- /AlloyReact/modules/_protected/CMS/web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AlloyReact/modules/_protected/EPiServer.Cms.TinyMce/EPiServer.Cms.TinyMce.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/modules/_protected/EPiServer.Cms.TinyMce/EPiServer.Cms.TinyMce.zip -------------------------------------------------------------------------------- /AlloyReact/modules/_protected/EPiServer.Cms.TinyMce/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AlloyReact/modules/_protected/EPiServer.Packaging.UI/EPiServer.Packaging.UI.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/modules/_protected/EPiServer.Packaging.UI/EPiServer.Packaging.UI.zip -------------------------------------------------------------------------------- /AlloyReact/modules/_protected/EPiServer.Packaging.UI/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AlloyReact/modules/_protected/EPiServer.Search.Cms/IndexContent.aspx: -------------------------------------------------------------------------------- 1 | <%@ Page Language="C#" AutoEventWireup="false" CodeBehind="IndexContent.aspx.cs" Inherits="EPiServer.UI.Admin.IndexContent" Title="Index Content" %> 2 | 3 | 4 |
    5 |

    <%: Translate("/admin/indexcontent/latestindexing") %> 6 | 7 |

    8 | 9 |
    10 | <%: Translate("/admin/indexcontent/resetinfo") %> 11 |
    12 | 13 |
    14 |
    15 |
    16 | -------------------------------------------------------------------------------- /AlloyReact/modules/_protected/EPiServer.Search.Cms/module.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /AlloyReact/modules/_protected/EPiServer.XForms/EPiServer.XForms.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/modules/_protected/EPiServer.XForms/EPiServer.XForms.zip -------------------------------------------------------------------------------- /AlloyReact/modules/_protected/EPiServer.XForms/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AlloyReact/modules/_protected/Shell/Shell.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/episerver/AlloyReact/d0f52b1338ab306f4dc18f7894ecffe8a9f31521/AlloyReact/modules/_protected/Shell/Shell.zip -------------------------------------------------------------------------------- /AlloyReact/modules/_protected/Shell/web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AlloyReact/modules/_protected/repository.config: -------------------------------------------------------------------------------- 1 |  2 | -------------------------------------------------------------------------------- /AlloyReact/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alloy-react", 3 | "version": "1.0.0", 4 | "description": "Alloy-based example site with React components", 5 | "main": "index.js", 6 | "private": true, 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "react": "^15.5.4", 14 | "react-dom": "^15.5.4" 15 | }, 16 | "devDependencies": { 17 | "babel-core": "^6.24.1", 18 | "babel-loader": "^7.0.0", 19 | "babel-preset-env": "^1.4.0", 20 | "babel-preset-react": "^6.24.1", 21 | "gulp": "^3.9.1", 22 | "gulp-util": "^3.0.8", 23 | "webpack": "^2.6.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /AlloyReact/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | var APP_DIR = path.resolve(__dirname, "Static/react"); 4 | var BUILD_DIR = path.resolve(__dirname, "Static/js"); 5 | 6 | module.exports = { 7 | entry: { 8 | react: APP_DIR + "/index.js" 9 | }, 10 | output: { 11 | path: BUILD_DIR, 12 | filename: "[name].bundle.js", 13 | publicPath: BUILD_DIR, 14 | chunkFilename: "[id].bundle.js" 15 | }, 16 | watch: true, 17 | devtool: "source-map", 18 | resolve: { 19 | extensions: [".js", ".jsx"] 20 | }, 21 | module: { 22 | loaders: [ 23 | { 24 | test: /\.jsx?$/, 25 | exclude: /node_modules/, 26 | loader: "babel-loader" 27 | }] 28 | } 29 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # On-Page Edit examples in Alloy using React 2 | 3 | Example site for showing how to use On-Page Edit together with React. Please help out by contributing more examples through PR's! 4 | 5 | _Note: You'll need CMS UI >=11.4.0 and while this is in Beta you [need to enable the features](https://world.episerver.com/documentation/Items/Installation-Instructions/beta-features/)._ 6 | 7 | ## Site login 8 | User: cmsadmin 9 | 10 | Password: sparr0wHawk! 11 | 12 | ## Examples 13 | 14 | ### Overview 15 | * Webpack is used for transpiling React 16 | * React components are mounted on-demand, since we don't have a single root component 17 | * Inside `/Static/react/index.js` there is code which mounts a React component in any HTML container element with a `data-react-component` attribute 18 | * To simplify rendering container elements, there is an HTML helper method called `ReactComponentFor` in `/Helpers/HtmlHelpers.cs` 19 | * The HTML helper makes sure that React scripts are added to the page, whenever at least one React component should be rendered 20 | * The script resource is defined in `module.config` 21 | 22 | ### Rendering some number 23 | An `int` property called _SomeNumber_ has been added to the `StandardPage` page type. It is decorated with a UI hint called _ReactNumber_. 24 | 25 | Have a look at the display template: 26 | `/Views/Shared/DisplayTemplates/ReactNumber.cshtml` 27 | 28 | You'll notice the attributes used to trigger on-page editing features. 29 | 30 | You can see it in action by on-page editing this page: 31 | http://localhost:27399/en/about-us/news-events/press-releases/ 32 | 33 | ### Editing a block-type property 34 | The `NewsList` property of the `NewsPage` page type is now rendered by a React component, instead of the Razor view from the default Alloy templates. 35 | 36 | Have a look at its display template: 37 | `/Views/Shared/DisplayTemplates/PageListBlock.cshtml` 38 | 39 | You can see it in action by on-page editing this page: 40 | http://localhost:27399/en/alloy-plan/download-alloy-plan/ 41 | 42 | ### Editing a content that has a dynamic DOM 43 | The block type `ThreeKeyFactsBlock` is rendered as a React component and the user can select what properties to be shown. This requires that the On Page Edit mode (OPE) can update the property overlays so that the editor is editing the correct properties. 44 | 45 | Have a look at the component: 46 | `/Static/react/ThreeKeyFacts.jsx` 47 | 48 | To see it in action you need to create a block of type `ThreeKeyFactsBlock`. 49 | 50 | ## Noteworthy files 51 | * `/Static/react/index.js` 52 | * `/Static/react/ReactNumber.jsx` 53 | * `/Static/react/PageListBlock.jsx` 54 | * `/Static/react/ThreeKeyFacts.jsx` 55 | * `/Views/Shared/DisplayTemplates/ReactNumber.cshtml` 56 | * `/Views/Shared/DisplayTemplates/PageListBlock.cshtml` 57 | 58 | ## Tip 59 | The first commit ("Initial checkin") to this repo is a standard Alloy website. If you compare to the first commit, you'll be able to see what was added or changed for these examples. --------------------------------------------------------------------------------