├── .gitattributes ├── .gitignore ├── README.md ├── appveyor.yml ├── lib ├── Microsoft.Html.Core.dll └── Microsoft.Web.Core.dll ├── src ├── 404.cshtml ├── Web.config ├── app_code │ ├── Helpers.cshtml │ ├── MarkdownPage.cs │ ├── PageParser.cs │ └── PageSystem.cs ├── bin │ ├── Markdig.dll │ ├── Markdig.dll.refresh │ ├── Microsoft.Html.Core.dll │ ├── Microsoft.Html.Core.dll.refresh │ ├── Microsoft.Web.Core.dll │ ├── Microsoft.Web.Core.dll.refresh │ ├── Microsoft.Web.Infrastructure.dll │ ├── Microsoft.Web.Infrastructure.dll.refresh │ ├── System.Web.Helpers.dll │ ├── System.Web.Helpers.dll.refresh │ ├── System.Web.Razor.dll │ ├── System.Web.Razor.dll.refresh │ ├── System.Web.WebPages.Deployment.dll │ ├── System.Web.WebPages.Deployment.dll.refresh │ ├── System.Web.WebPages.Razor.dll │ ├── System.Web.WebPages.Razor.dll.refresh │ ├── System.Web.WebPages.dll │ ├── System.Web.WebPages.dll.refresh │ ├── WebMarkupMin.Core.dll │ ├── WebMarkupMin.Core.dll.refresh │ ├── WebMarkupMin.Web.dll │ └── WebMarkupMin.Web.dll.refresh ├── gulpfile.js ├── index.cshtml ├── package.json ├── packages.config ├── pages │ ├── Commands │ │ ├── _assets │ │ │ └── index-package-managers.png │ │ ├── index.md │ │ ├── vsct-file.md │ │ └── walkthrough.md │ ├── Editor │ │ ├── _assets │ │ │ └── index-package-managers.png │ │ ├── index.md │ │ ├── intellisense.md │ │ └── syntax-highlighting.md │ ├── GettingStarted │ │ ├── _assets │ │ │ └── index-package-managers.png │ │ ├── index.md │ │ └── walkthrough.md │ ├── Performance │ │ ├── _assets │ │ │ └── index-package-managers.png │ │ ├── asyncpackage.md │ │ ├── autoload.md │ │ └── index.md │ ├── _assets │ │ ├── hero-1024.jpg │ │ ├── hero-1280.jpg │ │ ├── hero-1600.jpg │ │ ├── hero-1920.jpg │ │ ├── hero-667.jpg │ │ └── hero-original.jpg │ └── index.md ├── search.cshtml ├── themes │ └── standard │ │ ├── _Layout.cshtml │ │ ├── favicon │ │ ├── android-chrome-144x144.png │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-36x36.png │ │ ├── android-chrome-48x48.png │ │ ├── android-chrome-72x72.png │ │ ├── android-chrome-96x96.png │ │ ├── apple-touch-icon-114x114.png │ │ ├── apple-touch-icon-120x120.png │ │ ├── apple-touch-icon-144x144.png │ │ ├── apple-touch-icon-152x152.png │ │ ├── apple-touch-icon-180x180.png │ │ ├── apple-touch-icon-57x57.png │ │ ├── apple-touch-icon-60x60.png │ │ ├── apple-touch-icon-72x72.png │ │ ├── apple-touch-icon-76x76.png │ │ ├── apple-touch-icon-precomposed.png │ │ ├── apple-touch-icon.png │ │ ├── browserconfig.xml │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon-96x96.png │ │ ├── favicon.ico │ │ ├── manifest.json │ │ ├── mstile-144x144.png │ │ ├── mstile-150x150.png │ │ ├── mstile-310x150.png │ │ ├── mstile-310x310.png │ │ └── mstile-70x70.png │ │ ├── img │ │ ├── arrow.min.svg │ │ ├── arrow.png │ │ ├── arrow.svg │ │ ├── codeplex.min.svg │ │ ├── codeplex.png │ │ ├── codeplex.svg │ │ ├── github.min.svg │ │ ├── github.png │ │ ├── github.svg │ │ ├── microsoft.min.svg │ │ ├── microsoft.svg │ │ ├── nav-closed.min.svg │ │ ├── nav-closed.png │ │ ├── nav-closed.svg │ │ ├── nav-open.min.svg │ │ ├── nav-open.png │ │ ├── nav-open.svg │ │ ├── search.min.svg │ │ ├── search.png │ │ ├── search.svg │ │ ├── spinner.gif │ │ ├── vs.min.svg │ │ ├── vs.png │ │ └── vs.svg │ │ ├── js │ │ ├── dataService.js │ │ ├── menu.js │ │ ├── pinned.js │ │ └── search.js │ │ ├── less │ │ ├── breadcrumb.less │ │ ├── footer.less │ │ ├── global.less │ │ ├── header.less │ │ ├── main.less │ │ ├── mediaqueries.less │ │ ├── nav.less │ │ ├── search.less │ │ ├── site.less │ │ └── variables.less │ │ ├── output │ │ ├── site.css │ │ └── site.js │ │ └── page.cshtml └── views │ ├── appcache.cshtml │ ├── keywords.cshtml │ ├── opensearch.cshtml │ ├── robots.cshtml │ └── sitemap.cshtml ├── test ├── aspnet_compiler.exe └── test.ps1 └── vsext-docs.sln /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | .vs 6 | 7 | # Build results 8 | [Dd]ebug/ 9 | [Dd]ebugPublic/ 10 | [Rr]elease/ 11 | [Rr]eleases/ 12 | x64/ 13 | x86/ 14 | build/ 15 | bld/ 16 | **/[Bb]in/*.pdb 17 | **/[Bb]in/*.xml 18 | [Oo]bj/ 19 | 20 | # Roslyn cache directories 21 | *.ide/ 22 | 23 | # MSTest test Results 24 | [Tt]est[Rr]esult*/ 25 | [Bb]uild[Ll]og.* 26 | 27 | #NUNIT 28 | *.VisualState.xml 29 | TestResult.xml 30 | 31 | # Build Results of an ATL Project 32 | [Dd]ebugPS/ 33 | [Rr]eleasePS/ 34 | dlldata.c 35 | 36 | *_i.c 37 | *_p.c 38 | *_i.h 39 | *.ilk 40 | *.meta 41 | *.obj 42 | *.pch 43 | *.pdb 44 | *.pgc 45 | *.pgd 46 | *.rsp 47 | *.sbr 48 | *.tlb 49 | *.tli 50 | *.tlh 51 | *.tmp 52 | *.tmp_proj 53 | *.log 54 | *.vspscc 55 | *.vssscc 56 | .builds 57 | *.pidb 58 | *.svclog 59 | *.scc 60 | 61 | # Chutzpah Test files 62 | _Chutzpah* 63 | 64 | # Visual C++ cache files 65 | ipch/ 66 | *.aps 67 | *.ncb 68 | *.opensdf 69 | *.sdf 70 | *.cachefile 71 | 72 | # Visual Studio profiler 73 | *.psess 74 | *.vsp 75 | *.vspx 76 | 77 | # TFS 2012 Local Workspace 78 | $tf/ 79 | 80 | # Guidance Automation Toolkit 81 | *.gpState 82 | 83 | # ReSharper is a .NET coding add-in 84 | _ReSharper*/ 85 | *.[Rr]e[Ss]harper 86 | *.DotSettings.user 87 | 88 | # JustCode is a .NET coding addin-in 89 | .JustCode 90 | 91 | # TeamCity is a build add-in 92 | _TeamCity* 93 | 94 | # DotCover is a Code Coverage Tool 95 | *.dotCover 96 | 97 | # NCrunch 98 | _NCrunch_* 99 | .*crunch*.local.xml 100 | 101 | # MightyMoose 102 | *.mm.* 103 | AutoTest.Net/ 104 | 105 | # Web workbench (sass) 106 | .sass-cache/ 107 | 108 | # Installshield output folder 109 | [Ee]xpress/ 110 | 111 | # DocProject is a documentation generator add-in 112 | DocProject/buildhelp/ 113 | DocProject/Help/*.HxT 114 | DocProject/Help/*.HxC 115 | DocProject/Help/*.hhc 116 | DocProject/Help/*.hhk 117 | DocProject/Help/*.hhp 118 | DocProject/Help/Html2 119 | DocProject/Help/html 120 | 121 | # Click-Once directory 122 | publish/ 123 | 124 | # Publish Web Output 125 | *.[Pp]ublish.xml 126 | *.azurePubxml 127 | # TODO: Comment the next line if you want to checkin your web deploy settings 128 | # but database connection strings (with potential passwords) will be unencrypted 129 | *.pubxml 130 | *.publishproj 131 | 132 | # NuGet Packages 133 | *.nupkg 134 | # The packages folder can be ignored because of Package Restore 135 | **/packages/* 136 | # except build/, which is used as an MSBuild target. 137 | !**/packages/build/ 138 | # If using the old MSBuild-Integrated Package Restore, uncomment this: 139 | #!**/packages/repositories.config 140 | 141 | # Windows Azure Build Output 142 | csx/ 143 | *.build.csdef 144 | 145 | # Windows Store app package directory 146 | AppPackages/ 147 | 148 | # Others 149 | sql/ 150 | *.Cache 151 | ClientBin/ 152 | [Ss]tyle[Cc]op.* 153 | ~$* 154 | *~ 155 | *.dbmdl 156 | *.dbproj.schemaview 157 | *.pfx 158 | *.publishsettings 159 | node_modules/ 160 | 161 | # RIA/Silverlight projects 162 | Generated_Code/ 163 | 164 | # Backup & report files from converting an old project file 165 | # to a newer Visual Studio version. Backup files are not needed, 166 | # because we have git ;-) 167 | _UpgradeReport_Files/ 168 | Backup*/ 169 | UpgradeLog*.XML 170 | UpgradeLog*.htm 171 | 172 | # SQL Server files 173 | *.mdf 174 | *.ldf 175 | 176 | # Business Intelligence projects 177 | *.rdl.data 178 | *.bim.layout 179 | *.bim_*.settings 180 | 181 | # Microsoft Fakes 182 | FakesAssemblies/ 183 | 184 | # ========================= 185 | # Operating System Files 186 | # ========================= 187 | 188 | # OSX 189 | # ========================= 190 | 191 | .DS_Store 192 | .AppleDouble 193 | .LSOverride 194 | 195 | # Thumbnails 196 | ._* 197 | 198 | # Files that might appear on external disk 199 | .Spotlight-V100 200 | .Trashes 201 | 202 | # Directories potentially created on remote AFP share 203 | .AppleDB 204 | .AppleDesktop 205 | Network Trash Folder 206 | Temporary Items 207 | .apdisk 208 | 209 | # Windows 210 | # ========================= 211 | 212 | # Windows image file caches 213 | Thumbs.db 214 | ehthumbs.db 215 | 216 | # Folder config file 217 | Desktop.ini 218 | 219 | # Recycle Bin used on file shares 220 | $RECYCLE.BIN/ 221 | 222 | # Windows Installer files 223 | *.cab 224 | *.msi 225 | *.msm 226 | *.msp 227 | 228 | # Windows shortcuts 229 | *.lnk 230 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Visual Studio Extensibility 2 | 3 | [![Build status](https://ci.appveyor.com/api/projects/status/ekhjhyg5s6r2rkjq?svg=true)](https://ci.appveyor.com/project/madskristensen/vsext-docs) 4 | 5 | Website: [vsix.azurewebsites.net/](http://vsix.azurewebsites.net/) 6 | 7 | ### A cookbook 8 | 9 | - Lots of code snippets 10 | - Guide to performance tuning 11 | - Links to helpful tools -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | configuration: Release 3 | 4 | install: 5 | - npm install npm@3.10.8 -g 6 | - set PATH=%APPDATA%\npm;%PATH% 7 | - npm --version 8 | - cd src && npm install 9 | 10 | build: 11 | verbosity: minimal 12 | 13 | build_script: 14 | - nuget restore -verbosity quiet 15 | - test\aspnet_compiler -p src -v -u output 16 | - cd src && node_modules\.bin\gulp 17 | 18 | test_script: 19 | - ps: .\test\test.ps1 20 | -------------------------------------------------------------------------------- /lib/Microsoft.Html.Core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/lib/Microsoft.Html.Core.dll -------------------------------------------------------------------------------- /lib/Microsoft.Web.Core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/lib/Microsoft.Web.Core.dll -------------------------------------------------------------------------------- /src/404.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Configuration; 2 | @{ 3 | string status = Request.QueryString["status"] ?? "404"; 4 | Response.StatusCode = int.Parse(status); 5 | 6 | string title = "Page not found"; 7 | string desc = "It looks like I can't find this page"; 8 | 9 | if (Response.StatusCode != 404) 10 | { 11 | title = "Something went wrong"; 12 | desc = "We've recorded the error and a fix is coming."; 13 | } 14 | 15 | Page.Title = title; 16 | Page.Description = title; 17 | Page.ShowHero = true; 18 | @WriteContent(title, desc); 19 | 20 | Page.Theme = ConfigurationManager.AppSettings["theme"]; 21 | 22 | Layout = "~/themes/" + Page.Theme + "/_layout.cshtml"; 23 | } 24 | 25 | @helper WriteContent(string title, string content) { 26 |

@title

27 | 28 |
29 |

@content

30 |
31 | } -------------------------------------------------------------------------------- /src/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /src/app_code/Helpers.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Text.RegularExpressions; 2 | @using System.Drawing; 3 | @using System.Configuration; 4 | 5 | @functions { 6 | public static string Fingerprint(string rootRelativePath) 7 | { 8 | if (Request.IsLocal) 9 | { 10 | return rootRelativePath; // So Browser Link's CSS auto-sync works 11 | } 12 | 13 | string relative = VirtualPathUtility.ToAbsolute("~" + rootRelativePath); 14 | string absolute = Server.MapPath(relative); 15 | 16 | if (!File.Exists(absolute)) 17 | { 18 | throw new Exception("File not found " + rootRelativePath); 19 | } 20 | 21 | DateTime date = File.GetLastWriteTime(absolute); 22 | int index = relative.LastIndexOf('.'); 23 | 24 | return relative.Insert(index, "_" + date.Ticks); 25 | } 26 | 27 | public static string CreateLink(MarkdownPage page) 28 | { 29 | List segments = new List(new[] { page.Slug }); 30 | MarkdownPage parent = page.Parent; 31 | 32 | while (parent != null) 33 | { 34 | segments.Add(parent.Slug); 35 | parent = parent.Parent; 36 | } 37 | 38 | string path = string.Join("/", segments.Reverse().Skip(1)); 39 | return "/" + (string.IsNullOrEmpty(path) ? string.Empty : path + "/"); 40 | } 41 | 42 | public static IEnumerable GetAllPages(MarkdownPage parent, List list = null) 43 | { 44 | if (list == null) 45 | list = new List(); 46 | 47 | list.Add(parent); 48 | 49 | foreach (MarkdownPage child in parent.Children) 50 | { 51 | GetAllPages(child, list); 52 | } 53 | 54 | return list; 55 | } 56 | 57 | public static string GetDimensions(string relative) 58 | { 59 | string absolute = Server.MapPath(relative); 60 | var img = Bitmap.FromFile(absolute); 61 | 62 | return string.Format("width=\"{0}\" height=\"{1}\"", img.Width, img.Height); 63 | } 64 | 65 | public static bool IsMenuItemOpen(MarkdownPage page) 66 | { 67 | MarkdownPage current = PageSystem.GetCurrentPage(Request); 68 | 69 | if (page == current && page.Children.Any()) 70 | return true; 71 | 72 | foreach (MarkdownPage child in page.Children) 73 | { 74 | if (child == current) 75 | return true; 76 | } 77 | 78 | return false; 79 | } 80 | } 81 | 82 | @helper RenderMenu(IEnumerable pages) 83 | { 84 |
    85 | @foreach (MarkdownPage page in pages.Where(p => p.ShowInMenu)) 86 | { 87 |
  • 88 | @CreateAnchorTag(page) 89 | @if (page.Children.Count > 0) 90 | { 91 | @RenderMenu(page.Children) 92 | } 93 |
  • 94 | } 95 |
96 | } 97 | 98 | @helper RenderBreadcrumb(MarkdownPage page) 99 | { 100 | List list = new List(new[] { page }); 101 | while (page.Parent != null) 102 | { 103 | list.Add(page.Parent); 104 | page = page.Parent; 105 | } 106 | 107 | 113 | } 114 | 115 | @helper CreateAnchorTag(MarkdownPage page) 116 | { 117 | string link = CreateLink(page); 118 | string className = page == PageSystem.GetCurrentPage(Request) ? "active" : null; 119 | 120 | @page.Title 121 | } 122 | 123 | @helper RenderContent(MarkdownPage page) 124 | { 125 | Regex regex = new Regex(@"src)=""(?[^\""']+)"".*?>"); 126 | Regex h2rgx = new Regex(@"<(?(h2|h3))>(?[^<]+)<(?/\1)>"); 127 | string baseFolder = ConfigurationManager.AppSettings["pageFolder"].Trim('~', '/'); 128 | 129 | string html = regex.Replace(page.Content, delegate (Match match) 130 | { 131 | string value = match.Value; 132 | string href = match.Groups["href"].Value; 133 | 134 | if (href.StartsWith("_assets")) 135 | { 136 | string root = page.FileName ?? ""; 137 | int index = root.LastIndexOf('/') + 1; 138 | string relative = "/" + baseFolder + root.Substring(0, index) + href; 139 | string newHref = Fingerprint(relative); 140 | string dimensions = GetDimensions(relative); 141 | string result = value.Replace(" src=\"" + href, " " + dimensions + " src=\"" + newHref); 142 | 143 | return result; 144 | } 145 | 146 | return value; 147 | }); 148 | 149 | html = h2rgx.Replace(html, delegate (Match match) 150 | { 151 | string value = match.Value; 152 | string inner = match.Groups["inner"].Value; 153 | string id = inner.Replace(" ", "-").ToLowerInvariant(); 154 | string result = value.Replace(inner, "" + inner + ""); 155 | 156 | return result; 157 | }); 158 | 159 | @Html.Raw(html) 160 | } -------------------------------------------------------------------------------- /src/app_code/MarkdownPage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | public class MarkdownPage 5 | { 6 | public MarkdownPage() 7 | { 8 | Children = new List(); 9 | } 10 | 11 | public string Title { get; set; } 12 | public string Description { get; set; } 13 | public string Keywords { get; set; } 14 | public string Slug { get; set; } 15 | public string Content { get; set; } 16 | public DateTime DateModified { get; set; } 17 | public MarkdownPage Parent { get; set; } 18 | public List Children { get; private set; } 19 | public string FileName { get; set; } 20 | public int Order { get; set; } 21 | public bool ShowInMenu { get; set; } 22 | 23 | public override string ToString() 24 | { 25 | return Title; 26 | } 27 | } 28 | 29 | public class PageComparer : IComparer 30 | { 31 | public int Compare(MarkdownPage x, MarkdownPage y) 32 | { 33 | if (x.Order == y.Order) 34 | return 0; 35 | 36 | if (x.Order > y.Order) 37 | return 1; 38 | 39 | return -1; 40 | } 41 | } -------------------------------------------------------------------------------- /src/app_code/PageParser.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Linq; 4 | using Microsoft.Html.Core.Tree; 5 | using Microsoft.Html.Core.Tree.Nodes; 6 | using Microsoft.Web.Core.Text; 7 | using Markdig; 8 | 9 | public class PageParser 10 | { 11 | private const string _index = "index.md"; 12 | private static MarkdownPipeline _pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build(); 13 | 14 | public PageParser(string baseDirectory) 15 | { 16 | BaseDirectory = baseDirectory; 17 | IsValid = true; 18 | ValidationMessages = new List(); 19 | } 20 | 21 | public bool IsValid { get; private set; } 22 | public List ValidationMessages { get; private set; } 23 | public string BaseDirectory { get; private set; } 24 | 25 | public MarkdownPage Parse() 26 | { 27 | return RecursiveFindChildren(BaseDirectory, null); 28 | } 29 | 30 | private MarkdownPage RecursiveFindChildren(string directory, MarkdownPage parent) 31 | { 32 | string index = Path.Combine(directory, _index); 33 | MarkdownPage newParent = ParsePage(index); 34 | ValidatePage(newParent); 35 | newParent.Parent = parent; 36 | 37 | foreach (string file in Directory.EnumerateFiles(directory, "*.md").Where(f => Path.GetFileName(f) != _index)) 38 | { 39 | MarkdownPage child = ParsePage(file); 40 | child.Parent = newParent; 41 | ValidatePage(child); 42 | newParent.Children.Add(child); 43 | } 44 | 45 | foreach (string childDir in GetChildDirectories(directory)) 46 | { 47 | RecursiveFindChildren(childDir, newParent); 48 | } 49 | 50 | if (parent != null) 51 | { 52 | parent.Children.Add(newParent); 53 | parent.Children.Sort(new PageComparer()); 54 | } 55 | 56 | newParent.Children.Sort(new PageComparer()); 57 | 58 | return newParent; 59 | } 60 | 61 | private static IEnumerable GetChildDirectories(string parentDirectory) 62 | { 63 | return Directory.EnumerateDirectories(parentDirectory).Where(d => !new DirectoryInfo(d).Name.StartsWith("_")); 64 | } 65 | 66 | private MarkdownPage ParsePage(string fileName) 67 | { 68 | string html = Markdown.ToHtml(File.ReadAllText(fileName), _pipeline); 69 | 70 | HtmlTree tree = new HtmlTree(new TextStream(html)); 71 | tree.Build(); 72 | 73 | ElementNode firstChild = tree.RootNode.Children[0]; 74 | ElementNode prop = firstChild.Children[0]; 75 | 76 | MarkdownPage page = new MarkdownPage(); 77 | page.Title = AttrValue(prop, "pageTitle", Path.GetFileNameWithoutExtension(fileName)); 78 | page.Description = AttrValue(prop, "description", page.Title); 79 | page.Content = html.Substring(firstChild.End, tree.RootNode.Length - firstChild.End).Trim(); 80 | page.Keywords = AttrValue(prop, "keywords", page.Title); 81 | page.Slug = AttrValue(prop, "slug", page.Title.ToLowerInvariant()); 82 | page.DateModified = File.GetLastWriteTime(fileName); 83 | page.FileName = fileName.Replace(BaseDirectory, string.Empty).Replace("\\", "/"); 84 | page.ShowInMenu = Path.GetFileName(fileName).StartsWith("_") ? false : true; 85 | 86 | if (prop.GetAttribute("order") != null) 87 | page.Order = int.Parse(prop.GetAttribute("order").Value); 88 | else 89 | page.Order = 1000 + page.Title[0]; 90 | 91 | return page; 92 | } 93 | 94 | public static string AttrValue(ElementNode element, string attributeName, string defaultValue = null) 95 | { 96 | AttributeNode attr = element.GetAttribute(attributeName); 97 | return attr != null ? attr.Value : defaultValue; 98 | } 99 | 100 | private void ValidatePage(MarkdownPage page) 101 | { 102 | if (string.IsNullOrEmpty(page.Title)) 103 | AddValidationError(page, "Title must be set"); 104 | 105 | if (string.IsNullOrEmpty(page.Description)) 106 | AddValidationError(page, "Description must be set"); 107 | 108 | if (string.IsNullOrEmpty(page.Slug)) 109 | AddValidationError(page, "Slug must be set"); 110 | else if (page.Slug.Any(c => char.IsUpper(c) || char.IsWhiteSpace(c) || char.IsSymbol(c))) 111 | AddValidationError(page, "Slug must be alphanumeric and lower case only"); 112 | 113 | if (string.IsNullOrEmpty(page.Keywords) || page.Keywords.Count(c => c == ',') < 2) 114 | AddValidationError(page, "At least 3 comma separated keywords must be specified"); 115 | } 116 | 117 | private void AddValidationError(MarkdownPage page, string message) 118 | { 119 | ValidationMessages.Add(string.Format(message + " | " + page.FileName)); 120 | IsValid = false; 121 | } 122 | } -------------------------------------------------------------------------------- /src/app_code/PageSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Configuration; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Web; 6 | using System.Web.Caching; 7 | using System.Web.Hosting; 8 | 9 | public class PageSystem 10 | { 11 | public const string CACHE_KEY = "indexpage"; 12 | private static string _folder = HostingEnvironment.MapPath(ConfigurationManager.AppSettings.Get("pageFolder")); 13 | 14 | public static MarkdownPage IndexPage 15 | { 16 | get 17 | { 18 | if (HttpRuntime.Cache[CACHE_KEY] == null) 19 | { 20 | string[] files = Directory.GetDirectories(_folder, "*", SearchOption.AllDirectories).Union(new[] { _folder }).ToArray(); 21 | HttpRuntime.Cache.Insert(CACHE_KEY, Parse(), new CacheDependency(files)); 22 | } 23 | 24 | return (MarkdownPage)HttpRuntime.Cache[CACHE_KEY]; 25 | } 26 | } 27 | 28 | private static MarkdownPage Parse() 29 | { 30 | string directory = HostingEnvironment.MapPath("~/pages"); 31 | PageParser parser = new PageParser(directory); 32 | MarkdownPage index = parser.Parse(); 33 | 34 | if (!parser.IsValid) 35 | { 36 | var args = parser.ValidationMessages.Select(m => string.Join("in", m.Split('|'))); 37 | throw new Exception(string.Join(Environment.NewLine, args)); 38 | } 39 | 40 | return index; 41 | } 42 | 43 | public static MarkdownPage GetCurrentPage(HttpRequestBase request) 44 | { 45 | string raw = request.QueryString["path"]; 46 | 47 | if (string.IsNullOrWhiteSpace(raw)) 48 | return IndexPage; 49 | 50 | try { 51 | string[] segments = raw.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries); 52 | 53 | MarkdownPage page = IndexPage; 54 | 55 | foreach (string segment in segments) 56 | { 57 | page = page.Children.First(c => c.Slug.Equals(segment, StringComparison.OrdinalIgnoreCase)); 58 | } 59 | 60 | return page; 61 | } 62 | catch (Exception ex) 63 | { 64 | throw new HttpException(404, "Page not found", ex); 65 | } 66 | } 67 | 68 | public static string GetEditPage(MarkdownPage page) 69 | { 70 | return string.Format(ConfigurationManager.AppSettings.Get("editUrl"), page.FileName); 71 | } 72 | 73 | public static DateTime SetCacheHeaders(HttpContextBase context) 74 | { 75 | string[] allFiles = Directory.GetFiles(context.Server.MapPath("~/"), "*.*", SearchOption.AllDirectories); 76 | DateTime lastModified = allFiles.Max(f => File.GetLastWriteTime(f)); 77 | HttpResponseBase response = context.Response; 78 | HttpRequestBase request = context.Request; 79 | lastModified = new DateTime(lastModified.Year, lastModified.Month, lastModified.Day, lastModified.Hour, lastModified.Minute, lastModified.Second); 80 | 81 | string incomingDate = request.Headers["If-Modified-Since"]; 82 | 83 | response.Cache.SetLastModified(lastModified); 84 | 85 | DateTime testDate = DateTime.MinValue; 86 | 87 | if (DateTime.TryParse(incomingDate, out testDate) && testDate == lastModified) 88 | { 89 | response.ClearContent(); 90 | response.StatusCode = (int)System.Net.HttpStatusCode.NotModified; 91 | response.SuppressContent = true; 92 | } 93 | 94 | if (!request.IsLocal) 95 | { 96 | response.Cache.SetValidUntilExpires(true); 97 | response.Cache.SetCacheability(HttpCacheability.Public); 98 | response.Cache.VaryByParams["path"] = true; 99 | response.Cache.VaryByHeaders["X-Content-Only"] = true; 100 | response.AddFileDependencies(allFiles); 101 | response.Cache.SetLastModifiedFromFileDependencies(); 102 | response.Cache.SetMaxAge(TimeSpan.FromDays(7)); 103 | response.AppendHeader("Arr-Disable-Session-Affinity", "True"); // For Azure Websites 104 | } 105 | 106 | return lastModified; 107 | } 108 | } -------------------------------------------------------------------------------- /src/bin/Markdig.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/Markdig.dll -------------------------------------------------------------------------------- /src/bin/Markdig.dll.refresh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/Markdig.dll.refresh -------------------------------------------------------------------------------- /src/bin/Microsoft.Html.Core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/Microsoft.Html.Core.dll -------------------------------------------------------------------------------- /src/bin/Microsoft.Html.Core.dll.refresh: -------------------------------------------------------------------------------- 1 | ..\lib\Microsoft.Html.Core.dll -------------------------------------------------------------------------------- /src/bin/Microsoft.Web.Core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/Microsoft.Web.Core.dll -------------------------------------------------------------------------------- /src/bin/Microsoft.Web.Core.dll.refresh: -------------------------------------------------------------------------------- 1 | ..\lib\Microsoft.Web.Core.dll -------------------------------------------------------------------------------- /src/bin/Microsoft.Web.Infrastructure.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/Microsoft.Web.Infrastructure.dll -------------------------------------------------------------------------------- /src/bin/Microsoft.Web.Infrastructure.dll.refresh: -------------------------------------------------------------------------------- 1 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll -------------------------------------------------------------------------------- /src/bin/System.Web.Helpers.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/System.Web.Helpers.dll -------------------------------------------------------------------------------- /src/bin/System.Web.Helpers.dll.refresh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/System.Web.Helpers.dll.refresh -------------------------------------------------------------------------------- /src/bin/System.Web.Razor.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/System.Web.Razor.dll -------------------------------------------------------------------------------- /src/bin/System.Web.Razor.dll.refresh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/System.Web.Razor.dll.refresh -------------------------------------------------------------------------------- /src/bin/System.Web.WebPages.Deployment.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/System.Web.WebPages.Deployment.dll -------------------------------------------------------------------------------- /src/bin/System.Web.WebPages.Deployment.dll.refresh: -------------------------------------------------------------------------------- 1 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll -------------------------------------------------------------------------------- /src/bin/System.Web.WebPages.Razor.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/System.Web.WebPages.Razor.dll -------------------------------------------------------------------------------- /src/bin/System.Web.WebPages.Razor.dll.refresh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/System.Web.WebPages.Razor.dll.refresh -------------------------------------------------------------------------------- /src/bin/System.Web.WebPages.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/System.Web.WebPages.dll -------------------------------------------------------------------------------- /src/bin/System.Web.WebPages.dll.refresh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/System.Web.WebPages.dll.refresh -------------------------------------------------------------------------------- /src/bin/WebMarkupMin.Core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/WebMarkupMin.Core.dll -------------------------------------------------------------------------------- /src/bin/WebMarkupMin.Core.dll.refresh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/WebMarkupMin.Core.dll.refresh -------------------------------------------------------------------------------- /src/bin/WebMarkupMin.Web.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/WebMarkupMin.Web.dll -------------------------------------------------------------------------------- /src/bin/WebMarkupMin.Web.dll.refresh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/bin/WebMarkupMin.Web.dll.refresh -------------------------------------------------------------------------------- /src/gulpfile.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | var gulp = require("gulp"), 4 | less = require("gulp-less"), 5 | concat = require("gulp-concat"), 6 | uglify = require("gulp-uglify") 7 | 8 | var path = "./themes/standard/"; 9 | 10 | gulp.task("default", ["less", "scripts"]); 11 | 12 | gulp.task("scripts", function () { 13 | gulp.src([path + "js/*.js"]) 14 | .pipe(concat("site.js")) 15 | .pipe(uglify({ compress: true})) 16 | .pipe(gulp.dest(path + "output")); 17 | }); 18 | 19 | gulp.task("less", function () { 20 | gulp.src(path + "less/site.less") 21 | .pipe(less({ optimization: true, compress: true })) 22 | .on("error", swallowError) 23 | .pipe(gulp.dest(path + "output")); 24 | }); 25 | 26 | gulp.task("watch", ["less", "scripts"], function () { 27 | gulp.watch(path + "less/*.less", ["less"]); 28 | gulp.watch(path + "js/*.js", ["scripts"]); 29 | 30 | }); 31 | 32 | //#region Helpers 33 | 34 | function swallowError(error) { 35 | var msg = error.message.replace(process.cwd(), ""); 36 | console.log(msg); 37 | this.emit('end'); 38 | } 39 | 40 | //#endregion Helpers -------------------------------------------------------------------------------- /src/index.cshtml: -------------------------------------------------------------------------------- 1 | @using manager = System.Configuration.ConfigurationManager; 2 | @{ 3 | // Make sure all URLs end with a slash 4 | if (!Request.QueryString["path"].EndsWith("/")) 5 | { 6 | Response.RedirectPermanent(Request.QueryString["path"] + "/", true); 7 | } 8 | 9 | MarkdownPage page = PageSystem.GetCurrentPage(Request); 10 | 11 | Page.Title = page.Parent == null ? manager.AppSettings["name"] : page.Title + " - " + manager.AppSettings["name"]; 12 | Page.Description = page.Description; 13 | Page.Keywords = page.Keywords; 14 | Page.Theme = manager.AppSettings["theme"]; 15 | Page.ShowHero = page.Parent == null; 16 | 17 | MarkdownPage next = null; 18 | MarkdownPage prev = null; 19 | 20 | if (page.Parent == null) 21 | { 22 | next = page.Children.FirstOrDefault(); 23 | prev = null; 24 | } 25 | else 26 | { 27 | int index = page.Parent.Children.IndexOf(page); 28 | next = index < (page.Parent.Children.Count - 1) ? page.Parent.Children[index + 1] : null; 29 | prev = index > 0 ? page.Parent.Children[index - 1] : null; 30 | } 31 | 32 | if (Request.Headers["X-Content-Only"] == "1") 33 | { 34 | if (page.Parent != null) 35 | { 36 | @Helpers.RenderBreadcrumb(PageSystem.GetCurrentPage(Request)) 37 | } 38 | 39 | Response.Headers.Add("X-Title", HttpUtility.UrlEncode(Page.Title)); 40 | 41 | if (next != null) 42 | { 43 | Response.Headers.Add("X-Next", Helpers.CreateLink(next)); 44 | } 45 | if (prev != null) 46 | { 47 | Response.Headers.Add("X-Prev", Helpers.CreateLink(prev)); 48 | } 49 | } 50 | else 51 | { 52 | Layout = "~/themes/" + Page.Theme + "/_layout.cshtml"; 53 | } 54 | 55 | WebPageHttpHandler.DisableWebPagesResponseHeader = true; 56 | PageSystem.SetCacheHeaders(Context); 57 | } 58 | 59 | @section flipahead 60 | { 61 | @if (next != null) 62 | { 63 | 64 | } 65 | @if (prev != null) 66 | { 67 | 68 | } 69 | } 70 | 71 | @RenderPage("themes/" + Page.Theme + "/page.cshtml", page) -------------------------------------------------------------------------------- /src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vs", 3 | "version": "1.0.0", 4 | "private": true, 5 | "devDependencies": { 6 | "gulp": "3.9.1", 7 | "gulp-less": "3.3.0", 8 | "gulp-concat": "2.6.1", 9 | "gulp-uglify": "2.0.0" 10 | } 11 | } -------------------------------------------------------------------------------- /src/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/pages/Commands/_assets/index-package-managers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/pages/Commands/_assets/index-package-managers.png -------------------------------------------------------------------------------- /src/pages/Commands/index.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | ![Package Managers](_assets/index-package-managers.png) 10 | 11 | Join the Open Web and pull in libraries from all over. NuGet offers rich .NET server-side libraries, Bower connects you to the latest thinking in client-side JavaScript technology, and npm pulls in great tools 12 | and utilities. -------------------------------------------------------------------------------- /src/pages/Commands/vsct-file.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | ## Headline 9 | text 10 | 11 | -------------------------------------------------------------------------------- /src/pages/Commands/walkthrough.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | > links etc. to official MSDN article 10 | 11 | ## Headline 12 | text 13 | 14 | -------------------------------------------------------------------------------- /src/pages/Editor/_assets/index-package-managers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/pages/Editor/_assets/index-package-managers.png -------------------------------------------------------------------------------- /src/pages/Editor/index.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | ![Package Managers](_assets/index-package-managers.png) 10 | 11 | Join the Open Web and pull in libraries from all over. NuGet offers rich .NET server-side libraries, Bower connects you to the latest thinking in client-side JavaScript technology, and npm pulls in great tools 12 | and utilities. -------------------------------------------------------------------------------- /src/pages/Editor/intellisense.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | > links etc. to official MSDN article 9 | 10 | ## Headline 11 | text 12 | 13 | -------------------------------------------------------------------------------- /src/pages/Editor/syntax-highlighting.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | ## Headline 9 | text 10 | 11 | -------------------------------------------------------------------------------- /src/pages/GettingStarted/_assets/index-package-managers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/pages/GettingStarted/_assets/index-package-managers.png -------------------------------------------------------------------------------- /src/pages/GettingStarted/index.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | ![Package Managers](_assets/index-package-managers.png) 10 | 11 | Join the Open Web and pull in libraries from all over. NuGet offers rich .NET server-side libraries, Bower connects you to the latest thinking in client-side JavaScript technology, and npm pulls in great tools 12 | and utilities. -------------------------------------------------------------------------------- /src/pages/GettingStarted/walkthrough.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | ## Headline 9 | text 10 | 11 | -------------------------------------------------------------------------------- /src/pages/Performance/_assets/index-package-managers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/pages/Performance/_assets/index-package-managers.png -------------------------------------------------------------------------------- /src/pages/Performance/asyncpackage.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | > links etc. to official MSDN article 9 | 10 | ## Headline 11 | text 12 | 13 | -------------------------------------------------------------------------------- /src/pages/Performance/autoload.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | ## Headline 9 | text 10 | 11 | -------------------------------------------------------------------------------- /src/pages/Performance/index.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | ![Package Managers](_assets/index-package-managers.png) 10 | 11 | Join the Open Web and pull in libraries from all over. NuGet offers rich .NET server-side libraries, Bower connects you to the latest thinking in client-side JavaScript technology, and npm pulls in great tools 12 | and utilities. -------------------------------------------------------------------------------- /src/pages/_assets/hero-1024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/pages/_assets/hero-1024.jpg -------------------------------------------------------------------------------- /src/pages/_assets/hero-1280.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/pages/_assets/hero-1280.jpg -------------------------------------------------------------------------------- /src/pages/_assets/hero-1600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/pages/_assets/hero-1600.jpg -------------------------------------------------------------------------------- /src/pages/_assets/hero-1920.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/pages/_assets/hero-1920.jpg -------------------------------------------------------------------------------- /src/pages/_assets/hero-667.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/pages/_assets/hero-667.jpg -------------------------------------------------------------------------------- /src/pages/_assets/hero-original.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/pages/_assets/hero-original.jpg -------------------------------------------------------------------------------- /src/pages/index.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | ## Visual Studio Extensibility 9 | 10 | Extensions are add-ons that allow you to customize and enhance your experience in Visual Studio by adding new features or integrating existing tools. An extension can range in all levels of complexity, but its main purpose is to increase your productivity and cater to your workflow. There are thousands of extensions already available in the [Visual Studio Marketplace](https://marketplace.visualstudio.com/) for you to download and you can also create your own and upload them to share with other developers. -------------------------------------------------------------------------------- /src/search.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Configuration; 2 | @{ 3 | string q = (Request.QueryString["q"] ?? string.Empty).Trim(','); 4 | Page.Title = "Search results for '" + q + "'"; 5 | Page.Description = "Search results for " + q; 6 | Page.ShowHero = false; 7 | 8 | Page.Theme = ConfigurationManager.AppSettings["theme"]; 9 | 10 | if (Request.Headers["X-Content-Only"] != "1") 11 | { 12 | Layout = "~/themes/" + Page.Theme + "/_layout.cshtml"; 13 | } 14 | else 15 | { 16 | Response.Headers.Add("X-Title", Page.Title); 17 | } 18 | 19 | var results = GetResults(); 20 | } 21 | 22 | @functions 23 | { 24 | public IEnumerable GetResults() 25 | { 26 | string q = (Request.QueryString["q"] ?? string.Empty).Trim(','); 27 | 28 | var list = new Dictionary(); 29 | foreach (MarkdownPage page in Helpers.GetAllPages(PageSystem.IndexPage)) 30 | { 31 | int value = 0; 32 | 33 | if (page.Title.Contains(q)) 34 | value += 20; 35 | 36 | if (page.Description.Contains(q)) 37 | value += 10; 38 | 39 | if (page.Keywords.Contains(q)) 40 | value += 5; 41 | 42 | if (page.Content.Contains(q)) 43 | value += 3; 44 | 45 | if (value > 0) 46 | list.Add(page, value); 47 | } 48 | 49 | return list.OrderByDescending(k => k.Value).Select(k => k.Key); 50 | } 51 | } 52 | 53 | 57 | 58 | 59 |
60 |

@Page.Title

61 | @foreach (MarkdownPage page in results) 62 | { 63 | string prefix = page.Parent != null && page.Parent != PageSystem.IndexPage ? page.Parent.Title + " » " : null; 64 | 68 | } 69 | 70 | @if (!results.Any()) 71 | { 72 |

No results found for '@q'

73 | } 74 |
-------------------------------------------------------------------------------- /src/themes/standard/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Configuration; 2 | @{ 3 | string baseUrl = Request.Url.Scheme + "://" + Request.Url.Authority; 4 | } 5 | 6 | 7 | 8 | 9 | @Page.Title 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 | 51 | 52 | 53 | @RenderSection("flipahead", required: false) 54 | 55 | 56 | 57 |
58 |
59 | 63 |
64 | 65 |
66 |
67 |

Best practices cookbook

68 |

@ConfigurationManager.AppSettings["description"]

69 |
    70 |
  • Load packages correctly
  • 71 |
  • Code snippets for variuos scenarios
  • 72 |
  • Performance guide
  • 73 |
74 |
75 |
76 | 77 |
78 |
79 | @if (PageSystem.GetCurrentPage(Request).Parent != null) 80 | { 81 | @Helpers.RenderBreadcrumb(PageSystem.GetCurrentPage(Request)) 82 | } 83 | @RenderBody() 84 |
85 | 86 | 97 |
98 |
99 | 100 | 106 | 107 |
108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 |
119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /src/themes/standard/favicon/android-chrome-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/android-chrome-144x144.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/android-chrome-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/android-chrome-36x36.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/android-chrome-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/android-chrome-48x48.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/android-chrome-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/android-chrome-72x72.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/android-chrome-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/android-chrome-96x96.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | #2d89ef 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/themes/standard/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/favicon-96x96.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/favicon.ico -------------------------------------------------------------------------------- /src/themes/standard/favicon/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "icons": [ 3 | { 4 | "src": "themes\/standard\/favicon\/android-chrome-36x36.png", 5 | "sizes": "36x36", 6 | "type": "image\/png", 7 | "density": "0.75" 8 | }, 9 | { 10 | "src": "themes\/standard\/favicon\/android-chrome-48x48.png", 11 | "sizes": "48x48", 12 | "type": "image\/png", 13 | "density": "1.0" 14 | }, 15 | { 16 | "src": "themes\/standard\/favicon\/android-chrome-72x72.png", 17 | "sizes": "72x72", 18 | "type": "image\/png", 19 | "density": "1.5" 20 | }, 21 | { 22 | "src": "themes\/standard\/favicon\/android-chrome-96x96.png", 23 | "sizes": "96x96", 24 | "type": "image\/png", 25 | "density": "2.0" 26 | }, 27 | { 28 | "src": "themes\/standard\/favicon\/android-chrome-144x144.png", 29 | "sizes": "144x144", 30 | "type": "image\/png", 31 | "density": "3.0" 32 | }, 33 | { 34 | "src": "themes\/standard\/favicon\/android-chrome-192x192.png", 35 | "sizes": "192x192", 36 | "type": "image\/png", 37 | "density": "4.0" 38 | } 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /src/themes/standard/favicon/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/mstile-144x144.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/mstile-150x150.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/mstile-310x150.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/mstile-310x310.png -------------------------------------------------------------------------------- /src/themes/standard/favicon/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/favicon/mstile-70x70.png -------------------------------------------------------------------------------- /src/themes/standard/img/arrow.min.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/themes/standard/img/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/img/arrow.png -------------------------------------------------------------------------------- /src/themes/standard/img/arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /src/themes/standard/img/codeplex.min.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/themes/standard/img/codeplex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/img/codeplex.png -------------------------------------------------------------------------------- /src/themes/standard/img/codeplex.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/themes/standard/img/github.min.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/themes/standard/img/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/img/github.png -------------------------------------------------------------------------------- /src/themes/standard/img/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /src/themes/standard/img/microsoft.min.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/themes/standard/img/microsoft.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/themes/standard/img/nav-closed.min.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/themes/standard/img/nav-closed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/img/nav-closed.png -------------------------------------------------------------------------------- /src/themes/standard/img/nav-closed.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/themes/standard/img/nav-open.min.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/themes/standard/img/nav-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/img/nav-open.png -------------------------------------------------------------------------------- /src/themes/standard/img/nav-open.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/themes/standard/img/search.min.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/themes/standard/img/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/img/search.png -------------------------------------------------------------------------------- /src/themes/standard/img/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | 21 | 25 | 26 | 27 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/themes/standard/img/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/img/spinner.gif -------------------------------------------------------------------------------- /src/themes/standard/img/vs.min.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/themes/standard/img/vs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/src/themes/standard/img/vs.png -------------------------------------------------------------------------------- /src/themes/standard/img/vs.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 11 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/themes/standard/js/dataService.js: -------------------------------------------------------------------------------- 1 | var dataService = (function () { 2 | 3 | var pageCache = []; 4 | 5 | function getPage(url, callback) { 6 | 7 | var cached = pageCache[url]; 8 | 9 | if (cached) { 10 | callback(cached); 11 | return; 12 | } 13 | 14 | var xhr = new XMLHttpRequest(); 15 | xhr.open("GET", url, true); 16 | xhr.setRequestHeader("X-Content-Only", "1"); 17 | xhr.onreadystatechange = function () { 18 | if (xhr.readyState === 4 && xhr.status === 200) { 19 | var page = { url: url, content: xhr.responseText, title: decodeURIComponent(xhr.getResponseHeader("X-Title")), next: xhr.getResponseHeader("X-Next"), prev: xhr.getResponseHeader("X-Prev") }; 20 | pageCache[url] = page; 21 | callback(page); 22 | } 23 | }; 24 | 25 | xhr.send(); 26 | } 27 | 28 | function sendXhr(url, callback) { 29 | 30 | if (sessionStorage && sessionStorage[url]) { 31 | callback(sessionStorage[url]); 32 | return; 33 | } 34 | 35 | var http = new XMLHttpRequest(); 36 | http.open("GET", url, true); 37 | http.onreadystatechange = function () { 38 | if (http.readyState === 4 && http.status === 200) { 39 | callback(http.responseText); 40 | 41 | if (http.status === 200 && sessionStorage) 42 | sessionStorage[url] = http.responseText; 43 | } 44 | } 45 | 46 | http.send(null); 47 | } 48 | 49 | return { 50 | getPage: getPage, 51 | sendXhr: sendXhr, 52 | } 53 | 54 | })(); -------------------------------------------------------------------------------- /src/themes/standard/js/menu.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | (function () { 4 | 5 | var nav = document.getElementById("nav"), 6 | burger = document.getElementById("burger"), 7 | main = document.getElementsByTagName("main")[0], 8 | hero = document.getElementById("hero"), 9 | images = main.getElementsByTagName("img"), 10 | fadingInProgress = false; 11 | 12 | function syncMenu() { 13 | 14 | var open = nav.getElementsByClassName("open"); 15 | for (var i = 0; i < open.length; i++) { 16 | // this is for popstate to adjust the menu 17 | open[i].removeAttribute("class"); 18 | } 19 | 20 | if (location.pathname === "/") 21 | return; 22 | 23 | var active = nav.getElementsByClassName("active"); 24 | 25 | if (active.length === 0) 26 | return; 27 | 28 | var li = active[0].parentNode; 29 | 30 | if (!li) return; 31 | 32 | do { 33 | 34 | if (li.tagName === "LI" && li.childElementCount === 2) { 35 | li.className = "open"; 36 | li.removeAttribute("aria-hidden"); 37 | } 38 | 39 | li = li.parentNode; 40 | 41 | } while (li && li.parentNode !== nav); 42 | } 43 | 44 | function onBodyClick(e) { 45 | 46 | var href = e.target.getAttribute("href"); 47 | 48 | if (e.target.tagName !== "A" || href.indexOf("#") === 0) 49 | return; 50 | 51 | if (location.pathname === href) { 52 | e.preventDefault(); 53 | return; 54 | } 55 | 56 | if (e.target.id === burger.id) { 57 | onBurgerClick(e); 58 | } 59 | else if (e.target.nextElementSibling && e.target.nextElementSibling.tagName === "UL") { 60 | expandMenuParent(e); 61 | } 62 | else if (href.indexOf("://") === -1) { 63 | onLocalLinkClick(e, href); 64 | } 65 | } 66 | 67 | function expandMenuParent(e) { 68 | e.preventDefault(); 69 | 70 | var parent = e.target.parentNode; 71 | 72 | if (parent.tagName !== "LI") 73 | return; 74 | 75 | parent.className = parent.className === "" ? "open" : ""; 76 | 77 | // Close all other open menu items 78 | var open = nav.getElementsByClassName("open"); 79 | for (var i = 0; i < open.length; i++) { 80 | if (parent !== open[i]) 81 | open[i].removeAttribute("class"); 82 | } 83 | } 84 | 85 | function onLocalLinkClick(e, url) { 86 | e.preventDefault(); 87 | e.target.setAttribute("data-spinner", "true"); 88 | 89 | history.pushState("pushed", null, url); 90 | replaceContent(url, e.target); 91 | } 92 | 93 | function setMenuActive() { 94 | var actives = nav.getElementsByClassName("active"); 95 | for (var a = 0; a < actives.length; a++) { 96 | actives[a].removeAttribute("class"); 97 | } 98 | 99 | var current = nav.querySelector("[href='" + location.pathname + "']") 100 | if (current) 101 | current.className = "active"; 102 | } 103 | 104 | function replaceContent(url, target) { 105 | setMenuActive(); 106 | 107 | dataService.getPage(url, function (page) { 108 | 109 | main.style.opacity = 0; 110 | toggleHero(page.url); 111 | target && target.removeAttribute("data-spinner"); 112 | 113 | if (burger.offsetLeft > 0 || burger.offsetTop > 0) { // If small screen 114 | burger.nextElementSibling.style.visibility = ""; 115 | burger.nextElementSibling.nextElementSibling.style.visibility = ""; 116 | } 117 | 118 | setTimeout(function () { 119 | main.innerHTML = page.content; 120 | document.title = page.title.replace(/\+/g, " "); 121 | 122 | setTimeout(function () { 123 | var index = url.indexOf("#"); 124 | if (index > 0) { 125 | var target = document.getElementById(url.substring(index + 1)) 126 | target.scrollIntoView(); 127 | } 128 | }, 200) 129 | 130 | images = main.getElementsByTagName("img") 131 | fadeImagesIntoView(); 132 | setFlipAheadLinks(page.next, page.prev); 133 | 134 | main.style.opacity = 1; 135 | syncMenu(); 136 | 137 | }, 200); 138 | }); 139 | } 140 | 141 | function onBurgerClick(e) { 142 | e.preventDefault(); 143 | var ul = e.target.nextElementSibling.nextElementSibling; 144 | var visible = ul.style.visibility; 145 | ul.style.visibility = visible === "" ? "visible" : ""; 146 | 147 | var form = e.target.nextElementSibling; 148 | form.style.visibility = ul.style.visibility; 149 | } 150 | 151 | function setFlipAheadLinks(next, prev) { 152 | var nextLink = document.head.querySelector("link[rel=next]"); 153 | var prevLink = document.head.querySelector("link[rel=prev]"); 154 | 155 | setLink(nextLink, next, "next"); 156 | setLink(prevLink, prev, "prev"); 157 | 158 | function setLink(link, href, rel) { 159 | if (href) { 160 | link = link || createLink(rel, href); 161 | link.href = href; 162 | } 163 | else if (link) { 164 | link.parentNode.removeChild(link); 165 | } 166 | } 167 | 168 | function createLink(rel, href) { 169 | var link = document.createElement("link"); 170 | link.rel = rel; 171 | link.href = href; 172 | return document.head.appendChild(link); 173 | } 174 | } 175 | 176 | function toggleHero(href) { 177 | var showHero = (!href && location.pathname === "/") || href === "/"; 178 | hero.className = showHero ? "" : "hide"; 179 | } 180 | 181 | function fadeImagesIntoView() { 182 | if (fadingInProgress) return; 183 | 184 | fadingInProgress = true; 185 | 186 | setTimeout(function () { 187 | var height = window.innerHeight || document.documentElement.clientHeight; 188 | for (var i = 0; i < images.length; i++) { 189 | var image = images[i]; 190 | 191 | var rect = image.getBoundingClientRect(); 192 | image.style.opacity = rect.top >= -50 && rect.bottom <= height ? 1 : 0; 193 | 194 | if (rect.bottom > height) 195 | break; 196 | } 197 | 198 | fadingInProgress = false; 199 | }, 200); 200 | } 201 | 202 | document.body.addEventListener("click", onBodyClick, false); 203 | 204 | window.addEventListener("popstate", function (e) { 205 | if (e.state === "pushed") 206 | replaceContent(location.pathname); 207 | else 208 | console.log(e); 209 | }); 210 | 211 | window.addEventListener("scroll", fadeImagesIntoView, false); 212 | window.addEventListener("load", fadeImagesIntoView, false); 213 | })(); -------------------------------------------------------------------------------- /src/themes/standard/js/pinned.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | try { 4 | if (window.external.msIsSiteMode()) { 5 | ext = window.external; 6 | ext.msSiteModeCreateJumpList("Navigation"); 7 | 8 | var mainItems = document.querySelectorAll("#nav > ul > li > a"); 9 | 10 | for (var i = mainItems.length - 1; i > -1; i--) { 11 | var link = mainItems[i]; 12 | ext.msSiteModeAddJumpListItem(link.innerHTML, link.href, "/themes/standard/favicon/favicon.ico"); 13 | } 14 | } 15 | } 16 | catch (e) { /* Not IE9+ on desktop */} 17 | 18 | })(); -------------------------------------------------------------------------------- /src/themes/standard/js/search.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | (function () { 4 | 5 | var searchField = document.getElementById("q"), 6 | searchButton = document.getElementById("searchbutton"), 7 | searchForm = document.getElementById("search"), 8 | datalist = document.getElementsByTagName("datalist")[0], 9 | hiddenLink; 10 | 11 | function search(e) { 12 | 13 | var q = searchField.value; 14 | e.preventDefault(); 15 | 16 | if (q.trim().length === 0) { 17 | searchField.focus(); 18 | return; 19 | } 20 | 21 | if (!hiddenLink) { 22 | hiddenLink = document.createElement("a"); 23 | hiddenLink.setAttribute("aria-hidden", "true"); 24 | hiddenLink.innerHTML = "Hidden link used by the site search"; 25 | hiddenLink.style.display = "none"; 26 | searchButton.parentNode.appendChild(hiddenLink); 27 | } 28 | 29 | // This will let menu.js handle the page load as if it was a link click. 30 | hiddenLink.href = "/search/" + encodeURIComponent(q); 31 | hiddenLink.click(); 32 | } 33 | 34 | function clear() { 35 | var path = location.pathname; 36 | 37 | setInterval(function () { 38 | if (location.pathname !== path) { 39 | path = location.pathname; 40 | searchField.value = ""; 41 | } 42 | }, 1000) 43 | } 44 | 45 | function onFocus(e) { 46 | 47 | if (datalist.childNodes.length > 0) 48 | return; 49 | 50 | dataService.sendXhr("/views/keywords.cshtml", function (data) { 51 | var keywords = JSON.parse(data); 52 | 53 | for (var i = 0; i < keywords.length; i++) { 54 | var keyword = keywords[i]; 55 | var option = document.createElement("option"); 56 | option.innerHTML = keyword; 57 | datalist.appendChild(option); 58 | } 59 | }); 60 | } 61 | 62 | searchForm.addEventListener("submit", search, false); 63 | searchField.addEventListener("focus", onFocus, false); 64 | window.addEventListener("load", clear, false); 65 | })(); -------------------------------------------------------------------------------- /src/themes/standard/less/breadcrumb.less: -------------------------------------------------------------------------------- 1 | #breadcrumb { 2 | list-style: none; 3 | padding: 0; 4 | margin: 30px 0 0 0; 5 | 6 | li { 7 | display: inline; 8 | 9 | &:not(:first-child):before { 10 | content: ' » '; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/themes/standard/less/footer.less: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | #contribute { 4 | padding: 0 0 0 25px; 5 | margin: 50px 0 30px 0; 6 | background: url(/themes/standard/img/github.min.svg) no-repeat left; 7 | clear: both; 8 | display: inline-block; 9 | } 10 | 11 | footer { 12 | background: @footer-background-color; 13 | margin: -(@footer-height + 1) 0 0 0; 14 | font-size: 90%; 15 | color: @footer-color; 16 | line-height: @footer-height; 17 | height: @footer-height; 18 | position: relative; 19 | clear: both; 20 | 21 | .ms { 22 | float: right; 23 | padding-left: 25px; 24 | color: #f6f6f6; 25 | background: url(/themes/standard/img/microsoft.min.svg) no-repeat left 16px; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/themes/standard/less/global.less: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | @-ms-viewport { 4 | width: device-width; 5 | } 6 | 7 | html, body { 8 | height: 100%; // for the sticky footer 9 | } 10 | 11 | body { 12 | margin: 0; 13 | overflow-y: scroll; 14 | background: #fff; 15 | font: 16px/1.5em "Segoe UI","Segoe WP Light","Segoe WP",Tahoma,Arial,sans-serif; 16 | color: @text-color; 17 | } 18 | 19 | a { 20 | -ms-touch-action: manipulation; 21 | touch-action: manipulation; 22 | color: @link-color; 23 | text-decoration: none; 24 | 25 | &:hover { 26 | color: @link-hover-color; 27 | } 28 | } 29 | 30 | h1, h2, h3, h4 { 31 | font-family: "Segoe UI Light","Segoe WP Light","Segoe UI","Segoe WP",Tahoma,Arial,sans-serif; 32 | font-weight: 400; 33 | margin: 25px 0; 34 | line-height: 1.2; 35 | 36 | a { 37 | color: @text-color; 38 | 39 | &:target { 40 | outline: none; 41 | } 42 | 43 | &:hover { 44 | color: @text-color; 45 | 46 | &:after { 47 | content: "§"; 48 | padding-left: 10px; 49 | color: @link-color; 50 | font-weight: bold; 51 | font-size: 85%; 52 | } 53 | } 54 | } 55 | // Don't show the link on the front page 56 | &:only-of-type a { 57 | cursor: default; 58 | 59 | &:after { 60 | content: ""; 61 | } 62 | } 63 | } 64 | 65 | h1 { 66 | font-size: 36px; 67 | } 68 | 69 | h2 { 70 | font-size: 30px; 71 | } 72 | 73 | h3 { 74 | font-size: 22px; 75 | } 76 | 77 | img { 78 | max-width: 100%; 79 | height: auto; 80 | } 81 | 82 | .content { 83 | min-height: 100%; // for the sticky footer 84 | position: relative; 85 | } 86 | 87 | li { 88 | padding: 1px 0; 89 | } 90 | 91 | .container { 92 | max-width: 960px; 93 | margin: 0 auto; 94 | padding: 0 @container-padding; 95 | } 96 | 97 | .download { 98 | font-size: 16px; 99 | background: url(/themes/standard/img/arrow.min.svg) no-repeat right center; 100 | color: #fff; 101 | padding-right: 30px; 102 | display: inline-block; 103 | 104 | &:hover { 105 | color: #fff; 106 | } 107 | } -------------------------------------------------------------------------------- /src/themes/standard/less/header.less: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | header { 4 | background: @header-background-color; 5 | color: @header-color; 6 | line-height: @header-height; 7 | height: @header-height; 8 | font-size: 1.4em; 9 | margin-bottom: 0; 10 | 11 | a { 12 | color: @header-color; 13 | 14 | &:hover { 15 | color: @header-color; 16 | } 17 | } 18 | 19 | .download { 20 | margin-right: 5px; 21 | } 22 | } 23 | 24 | #hero { 25 | background-repeat: no-repeat; 26 | background-position: left top; 27 | background-size: cover; 28 | width: 100%; 29 | color: white; 30 | background-color: #0c0c0c; 31 | text-shadow: 1px 1px #0c0c0c; 32 | overflow: hidden; 33 | max-height: 300px; 34 | -moz-transition: max-height .4s linear; 35 | -o-transition: max-height .4s linear; 36 | -webkit-transition: max-height .4s linear; 37 | transition: max-height .4s linear; 38 | will-change: max-height; 39 | 40 | h1 { 41 | margin: @container-padding 0 0 0; 42 | } 43 | 44 | p { 45 | font-size: 18px; 46 | margin-right: @menu-width + 40px; 47 | } 48 | 49 | ul { 50 | margin: 0 0 @container-padding 0; 51 | } 52 | 53 | &.hide { 54 | max-height: 0; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/themes/standard/less/main.less: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | main { 4 | display: block; 5 | min-height: 500px; 6 | margin-right: @menu-width + 40px; 7 | padding-bottom: @footer-height; 8 | opacity: 1; 9 | -moz-transition: opacity .3s ease; 10 | -o-transition: opacity .3s ease; 11 | -webkit-transition: opacity .3s ease; 12 | transition: opacity .3s ease; 13 | 14 | article > p { 15 | padding-bottom: 20px; 16 | border-bottom: 1px solid @menu-background-color; 17 | } 18 | 19 | article img { 20 | opacity: 0; 21 | -moz-transition: opacity 2s ease; 22 | -o-transition: opacity 2s ease; 23 | -webkit-transition: opacity 2s ease; 24 | transition: opacity 2s ease; 25 | } 26 | 27 | article ul { 28 | list-style: none; 29 | padding: 0 0 40px 0; 30 | 31 | a { 32 | padding-left: 25px; 33 | background: no-repeat left; 34 | } 35 | 36 | a[href*="github.com"] { 37 | background-image: url(/themes/standard/img/github.min.svg); 38 | } 39 | 40 | a[href*="visualstudiogallery.msdn.microsoft.com"] { 41 | background-image: url(/themes/standard/img/vs.min.svg); 42 | } 43 | 44 | a[href*="codeplex.com"] { 45 | background-image: url(/themes/standard/img/codeplex.min.svg); 46 | } 47 | } 48 | 49 | blockquote { 50 | border-left: 5px solid #D8D8D8; 51 | margin: 0; 52 | padding: 0 1em; 53 | line-height: 30px; 54 | } 55 | 56 | aside { 57 | overflow: hidden; 58 | 59 | h2 { 60 | padding-top: @container-padding; 61 | border-top: 1px solid @menu-background-color; 62 | } 63 | 64 | section { 65 | float: left; 66 | margin-right: 50px; 67 | 68 | h3 { 69 | margin: 0; 70 | } 71 | 72 | ul { 73 | padding: 0; 74 | } 75 | 76 | a { 77 | padding: 0; 78 | background: none !important; 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/themes/standard/less/mediaqueries.less: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | @break: 666px; 4 | 5 | @media only screen and (min-width : (@break + 1)) { 6 | 7 | .container { 8 | position: relative; 9 | } 10 | 11 | header .download { 12 | float: right; 13 | } 14 | } 15 | 16 | @media only screen and (min-width: 1801px) { 17 | #hero { 18 | background-image: url("/pages/_assets/hero-1920.jpg"); 19 | } 20 | } 21 | 22 | @media only screen and (max-width: 1800px) { 23 | #hero { 24 | background-image: url("/pages/_assets/hero-1600.jpg"); 25 | } 26 | } 27 | 28 | @media only screen and (max-width: 1440px) { 29 | #hero { 30 | background-image: url("/pages/_assets/hero-1280.jpg"); 31 | } 32 | } 33 | 34 | @media only screen and (max-width: 1200px) { 35 | #hero { 36 | background-image: url("/pages/_assets/hero-1024.jpg"); 37 | } 38 | } 39 | 40 | @media only screen and (max-width : @break) { 41 | 42 | header .download { 43 | display: none; 44 | } 45 | 46 | nav { 47 | top: @container-padding; 48 | right: 0; 49 | 50 | > ul { 51 | visibility: hidden; 52 | list-style: none; 53 | } 54 | 55 | #burger { 56 | display: inline; 57 | } 58 | } 59 | 60 | main { 61 | margin: 0; 62 | } 63 | 64 | #hero { 65 | background-image: url("/pages/_assets/hero-667.jpg"); 66 | 67 | p { 68 | margin-right: 0; 69 | } 70 | } 71 | 72 | #search { 73 | margin-top: 40px; 74 | visibility: hidden; 75 | } 76 | } 77 | 78 | @media print { 79 | main { 80 | margin: 0; 81 | } 82 | 83 | #breadcrumb, 84 | header, 85 | #contribute { 86 | display: none; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/themes/standard/less/nav.less: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | nav { 4 | position: absolute; 5 | top: 50px; 6 | right: @container-padding; 7 | width: @menu-width; 8 | 9 | #burger { 10 | display: none; 11 | color: @header-color; 12 | float: right; 13 | 14 | &:before { 15 | content: '☰ '; 16 | font-size: 15px; 17 | } 18 | } 19 | 20 | ul { 21 | list-style: none; 22 | padding: 0; 23 | display: block; 24 | 25 | li a { 26 | display: block; 27 | padding: 2px 0 0 30px; 28 | } 29 | 30 | ul { 31 | max-height: 0; 32 | overflow: hidden; 33 | -moz-transition: max-height .2s ease-in-out; 34 | -o-transition: max-height .2s ease-in-out; 35 | -webkit-transition: max-height .2s ease-in-out; 36 | transition: max-height .2s ease-in-out; 37 | 38 | li { 39 | display: none; 40 | font-size: 90%; 41 | 42 | &:last-child { 43 | margin-bottom: 10px; 44 | } 45 | } 46 | } 47 | } 48 | 49 | > ul { 50 | margin: 0; 51 | 52 | > li { 53 | border-bottom: 1px solid white; 54 | border-left: 4px solid @menu-background-color; 55 | padding: 5px 0 5px 0; 56 | background-color: @menu-background-color; 57 | 58 | > a { 59 | background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHN0eWxlIHR5cGU9InRleHQvY3NzIj4uaWNvbi1jYW52YXMtdHJhbnNwYXJlbnR7b3BhY2l0eTowO2ZpbGw6I0Y2RjZGNjt9IC5pY29uLXZzLW91dHtmaWxsOiNGNkY2RjY7fSAuaWNvbi12cy1iZ3tmaWxsOiM0MjQyNDI7fTwvc3R5bGU+PHBhdGggaWQ9ImNhbnZhcyIgZD0iTTE2IDE2SDBWMGgxNnYxNnoiIGNsYXNzPSJpY29uLWNhbnZhcy10cmFuc3BhcmVudCIvPjxwYXRoIGlkPSJvdXRsaW5lIiBkPSJNNSAxLjZMMTEuNCA4IDUgMTQuNFYxLjZ6IiBjbGFzcz0iaWNvbi12cy1vdXQiLz48cGF0aCBpZD0iaWNvbkJnIiBkPSJNNiA0djhsNC00LTQtNHptMSAyLjRMOC42IDggNyA5LjZWNi40eiIgY2xhc3M9Imljb24tdnMtYmciLz48L3N2Zz4=') /*/themes/standard/img/nav-closed.min.svg*/ no-repeat 5px 6px; 60 | } 61 | } 62 | } 63 | 64 | .open { 65 | background-color: @menu-background-open-color; 66 | border-left: 4px solid @link-hover-color; 67 | 68 | > a { 69 | background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHN0eWxlIHR5cGU9InRleHQvY3NzIj4uaWNvbi1jYW52YXMtdHJhbnNwYXJlbnR7b3BhY2l0eTowO2ZpbGw6I0Y2RjZGNjt9IC5pY29uLXZzLW91dHtmaWxsOiNGNkY2RjY7fSAuaWNvbi12cy1iZ3tmaWxsOiM0MjQyNDI7fTwvc3R5bGU+PHBhdGggaWQ9ImNhbnZhcyIgZD0iTTE2IDE2SDBWMGgxNnYxNnoiIGNsYXNzPSJpY29uLWNhbnZhcy10cmFuc3BhcmVudCIvPjxwYXRoIGlkPSJvdXRsaW5lIiBkPSJNMi45IDExTDEyIDIuMDJWMTFIMi45eiIgY2xhc3M9Imljb24tdnMtb3V0Ii8+PHBhdGggaWQ9Imljb25CZyIgZD0iTTExIDEwSDUuMzRMMTEgNC40VjEweiIgY2xhc3M9Imljb24tdnMtYmciLz48L3N2Zz4=') /*/themes/standard/img/nav-open.min.svg*/; 70 | } 71 | 72 | > ul { 73 | max-height: 200px; 74 | 75 | li { 76 | display: block; 77 | } 78 | } 79 | } 80 | 81 | a { 82 | color: @menu-link-color; 83 | 84 | &.active { 85 | color: @link-color; 86 | } 87 | 88 | &[data-spinner] { 89 | position: relative; 90 | background: url(/themes/standard/img/spinner.gif) no-repeat 10px 7px; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/themes/standard/less/search.less: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | #search { 4 | border-bottom: 1px solid #fff; 5 | width: @menu-width; 6 | overflow: hidden; 7 | background: @menu-background-color; 8 | position: relative; 9 | 10 | label { 11 | display: none; 12 | } 13 | 14 | input[type=search] { 15 | padding: 6px 6px; 16 | background: transparent; 17 | font: inherit; 18 | width: 100%; 19 | float: left; 20 | padding-left: 35px; 21 | outline: none; 22 | border: none; 23 | } 24 | 25 | input[type=image] { 26 | border: 0; 27 | padding: 0; 28 | width: 16px; 29 | height: 16px; 30 | cursor: pointer; 31 | position: absolute; 32 | left: 10px; 33 | top: 10px; 34 | outline: none; 35 | color: transparent; 36 | } 37 | } 38 | 39 | #searchresults a { 40 | font-size: 1.3em; 41 | } 42 | 43 | input[type="search"]::-webkit-search-decoration, 44 | input[type="search"]::-webkit-search-results-button, 45 | input[type="search"]::-webkit-search-results-decoration { 46 | display: none; 47 | } 48 | -------------------------------------------------------------------------------- /src/themes/standard/less/site.less: -------------------------------------------------------------------------------- 1 | @import "global"; 2 | @import "header"; 3 | @import "breadcrumb"; 4 | @import "main"; 5 | @import "nav"; 6 | @import "footer"; 7 | @import "search"; 8 | @import "mediaqueries"; -------------------------------------------------------------------------------- /src/themes/standard/less/variables.less: -------------------------------------------------------------------------------- 1 | @text-color: #505050; 2 | 3 | @link-color: #007c9c; 4 | @link-hover-color: #00aedd; 5 | 6 | @header-color: #fff; 7 | @header-background-color: #68217a; 8 | @header-height: 60px; 9 | 10 | @container-padding: 19px; 11 | 12 | @menu-background-color: #f2eee6; 13 | @menu-background-open-color: #e0e7e3; 14 | @menu-link-color: #222; 15 | @menu-width: 200px; 16 | 17 | @footer-background-color: #56504a; 18 | @footer-color: lightgray; 19 | @footer-link-color: #fff; 20 | @footer-height: 50px; 21 | -------------------------------------------------------------------------------- /src/themes/standard/output/site.css: -------------------------------------------------------------------------------- 1 | @-ms-viewport{width:device-width}html,body{height:100%}body{margin:0;overflow-y:scroll;background:#fff;font:16px/1.5em "Segoe UI","Segoe WP Light","Segoe WP",Tahoma,Arial,sans-serif;color:#505050}a{-ms-touch-action:manipulation;touch-action:manipulation;color:#007c9c;text-decoration:none}a:hover{color:#00aedd}h1,h2,h3,h4{font-family:"Segoe UI Light","Segoe WP Light","Segoe UI","Segoe WP",Tahoma,Arial,sans-serif;font-weight:400;margin:25px 0;line-height:1.2}h1 a,h2 a,h3 a,h4 a{color:#505050}h1 a:target,h2 a:target,h3 a:target,h4 a:target{outline:none}h1 a:hover,h2 a:hover,h3 a:hover,h4 a:hover{color:#505050}h1 a:hover:after,h2 a:hover:after,h3 a:hover:after,h4 a:hover:after{content:"§";padding-left:10px;color:#007c9c;font-weight:bold;font-size:85%}h1:only-of-type a,h2:only-of-type a,h3:only-of-type a,h4:only-of-type a{cursor:default}h1:only-of-type a:after,h2:only-of-type a:after,h3:only-of-type a:after,h4:only-of-type a:after{content:""}h1{font-size:36px}h2{font-size:30px}h3{font-size:22px}img{max-width:100%;height:auto}.content{min-height:100%;position:relative}li{padding:1px 0}.container{max-width:960px;margin:0 auto;padding:0 19px}.download{font-size:16px;background:url(/themes/standard/img/arrow.min.svg) no-repeat right center;color:#fff;padding-right:30px;display:inline-block}.download:hover{color:#fff}header{background:#68217a;color:#fff;line-height:60px;height:60px;font-size:1.4em;margin-bottom:0}header a{color:#fff}header a:hover{color:#fff}header .download{margin-right:5px}#hero{background-repeat:no-repeat;background-position:left top;background-size:cover;width:100%;color:white;background-color:#0c0c0c;text-shadow:1px 1px #0c0c0c;overflow:hidden;max-height:300px;-moz-transition:max-height .4s linear;-o-transition:max-height .4s linear;-webkit-transition:max-height .4s linear;transition:max-height .4s linear;will-change:max-height}#hero h1{margin:19px 0 0 0}#hero p{font-size:18px;margin-right:240px}#hero ul{margin:0 0 19px 0}#hero.hide{max-height:0}#breadcrumb{list-style:none;padding:0;margin:30px 0 0 0}#breadcrumb li{display:inline}#breadcrumb li:not(:first-child):before{content:' » '}main{display:block;min-height:500px;margin-right:240px;padding-bottom:50px;opacity:1;-moz-transition:opacity .3s ease;-o-transition:opacity .3s ease;-webkit-transition:opacity .3s ease;transition:opacity .3s ease}main article>p{padding-bottom:20px;border-bottom:1px solid #f2eee6}main article img{opacity:0;-moz-transition:opacity 2s ease;-o-transition:opacity 2s ease;-webkit-transition:opacity 2s ease;transition:opacity 2s ease}main article ul{list-style:none;padding:0 0 40px 0}main article ul a{padding-left:25px;background:no-repeat left}main article ul a[href*="github.com"]{background-image:url(/themes/standard/img/github.min.svg)}main article ul a[href*="visualstudiogallery.msdn.microsoft.com"]{background-image:url(/themes/standard/img/vs.min.svg)}main article ul a[href*="codeplex.com"]{background-image:url(/themes/standard/img/codeplex.min.svg)}main blockquote{border-left:5px solid #D8D8D8;margin:0;padding:0 1em;line-height:30px}main aside{overflow:hidden}main aside h2{padding-top:19px;border-top:1px solid #f2eee6}main aside section{float:left;margin-right:50px}main aside section h3{margin:0}main aside section ul{padding:0}main aside section a{padding:0;background:none !important}nav{position:absolute;top:50px;right:19px;width:200px}nav #burger{display:none;color:#fff;float:right}nav #burger:before{content:'☰ ';font-size:15px}nav ul{list-style:none;padding:0;display:block}nav ul li a{display:block;padding:2px 0 0 30px}nav ul ul{max-height:0;overflow:hidden;-moz-transition:max-height .2s ease-in-out;-o-transition:max-height .2s ease-in-out;-webkit-transition:max-height .2s ease-in-out;transition:max-height .2s ease-in-out}nav ul ul li{display:none;font-size:90%}nav ul ul li:last-child{margin-bottom:10px}nav>ul{margin:0}nav>ul>li{border-bottom:1px solid white;border-left:4px solid #f2eee6;padding:5px 0 5px 0;background-color:#f2eee6}nav>ul>li>a{background:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHN0eWxlIHR5cGU9InRleHQvY3NzIj4uaWNvbi1jYW52YXMtdHJhbnNwYXJlbnR7b3BhY2l0eTowO2ZpbGw6I0Y2RjZGNjt9IC5pY29uLXZzLW91dHtmaWxsOiNGNkY2RjY7fSAuaWNvbi12cy1iZ3tmaWxsOiM0MjQyNDI7fTwvc3R5bGU+PHBhdGggaWQ9ImNhbnZhcyIgZD0iTTE2IDE2SDBWMGgxNnYxNnoiIGNsYXNzPSJpY29uLWNhbnZhcy10cmFuc3BhcmVudCIvPjxwYXRoIGlkPSJvdXRsaW5lIiBkPSJNNSAxLjZMMTEuNCA4IDUgMTQuNFYxLjZ6IiBjbGFzcz0iaWNvbi12cy1vdXQiLz48cGF0aCBpZD0iaWNvbkJnIiBkPSJNNiA0djhsNC00LTQtNHptMSAyLjRMOC42IDggNyA5LjZWNi40eiIgY2xhc3M9Imljb24tdnMtYmciLz48L3N2Zz4=') no-repeat 5px 6px}nav .open{background-color:#e0e7e3;border-left:4px solid #00aedd}nav .open>a{background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHN0eWxlIHR5cGU9InRleHQvY3NzIj4uaWNvbi1jYW52YXMtdHJhbnNwYXJlbnR7b3BhY2l0eTowO2ZpbGw6I0Y2RjZGNjt9IC5pY29uLXZzLW91dHtmaWxsOiNGNkY2RjY7fSAuaWNvbi12cy1iZ3tmaWxsOiM0MjQyNDI7fTwvc3R5bGU+PHBhdGggaWQ9ImNhbnZhcyIgZD0iTTE2IDE2SDBWMGgxNnYxNnoiIGNsYXNzPSJpY29uLWNhbnZhcy10cmFuc3BhcmVudCIvPjxwYXRoIGlkPSJvdXRsaW5lIiBkPSJNMi45IDExTDEyIDIuMDJWMTFIMi45eiIgY2xhc3M9Imljb24tdnMtb3V0Ii8+PHBhdGggaWQ9Imljb25CZyIgZD0iTTExIDEwSDUuMzRMMTEgNC40VjEweiIgY2xhc3M9Imljb24tdnMtYmciLz48L3N2Zz4=')}nav .open>ul{max-height:200px}nav .open>ul li{display:block}nav a{color:#222}nav a.active{color:#007c9c}nav a[data-spinner]{position:relative;background:url(/themes/standard/img/spinner.gif) no-repeat 10px 7px}#contribute{padding:0 0 0 25px;margin:50px 0 30px 0;background:url(/themes/standard/img/github.min.svg) no-repeat left;clear:both;display:inline-block}footer{background:#56504a;margin:-51px 0 0 0;font-size:90%;color:lightgray;line-height:50px;height:50px;position:relative;clear:both}footer .ms{float:right;padding-left:25px;color:#f6f6f6;background:url(/themes/standard/img/microsoft.min.svg) no-repeat left 16px}#search{border-bottom:1px solid #fff;width:200px;overflow:hidden;background:#f2eee6;position:relative}#search label{display:none}#search input[type=search]{padding:6px 6px;background:transparent;font:inherit;width:100%;float:left;padding-left:35px;outline:none;border:none}#search input[type=image]{border:0;padding:0;width:16px;height:16px;cursor:pointer;position:absolute;left:10px;top:10px;outline:none;color:transparent}#searchresults a{font-size:1.3em}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-results-button,input[type="search"]::-webkit-search-results-decoration{display:none}@media only screen and (min-width:667px){.container{position:relative}header .download{float:right}}@media only screen and (min-width:1801px){#hero{background-image:url("/pages/_assets/hero-1920.jpg")}}@media only screen and (max-width:1800px){#hero{background-image:url("/pages/_assets/hero-1600.jpg")}}@media only screen and (max-width:1440px){#hero{background-image:url("/pages/_assets/hero-1280.jpg")}}@media only screen and (max-width:1200px){#hero{background-image:url("/pages/_assets/hero-1024.jpg")}}@media only screen and (max-width:666px){header .download{display:none}nav{top:19px;right:0}nav>ul{visibility:hidden;list-style:none}nav #burger{display:inline}main{margin:0}#hero{background-image:url("/pages/_assets/hero-667.jpg")}#hero p{margin-right:0}#search{margin-top:40px;visibility:hidden}}@media print{main{margin:0}#breadcrumb,header,#contribute{display:none}} -------------------------------------------------------------------------------- /src/themes/standard/output/site.js: -------------------------------------------------------------------------------- 1 | var dataService=function(){function e(e,t){var a=n[e];if(a)return void t(a);var i=new XMLHttpRequest;i.open("GET",e,!0),i.setRequestHeader("X-Content-Only","1"),i.onreadystatechange=function(){if(4===i.readyState&&200===i.status){var a={url:e,content:i.responseText,title:decodeURIComponent(i.getResponseHeader("X-Title")),next:i.getResponseHeader("X-Next"),prev:i.getResponseHeader("X-Prev")};n[e]=a,t(a)}},i.send()}function t(e,t){if(sessionStorage&&sessionStorage[e])return void t(sessionStorage[e]);var n=new XMLHttpRequest;n.open("GET",e,!0),n.onreadystatechange=function(){4===n.readyState&&200===n.status&&(t(n.responseText),200===n.status&&sessionStorage&&(sessionStorage[e]=n.responseText))},n.send(null)}var n=[];return{getPage:e,sendXhr:t}}();!function(){function e(){for(var e=c.getElementsByClassName("open"),t=0;t0||u.offsetTop>0)&&(u.nextElementSibling.style.visibility="",u.nextElementSibling.nextElementSibling.style.visibility=""),setTimeout(function(){m.innerHTML=a.content,document.title=a.title.replace(/\+/g," "),setTimeout(function(){var e=t.indexOf("#");if(e>0){var n=document.getElementById(t.substring(e+1));n.scrollIntoView()}},200),g=m.getElementsByTagName("img"),d(),s(a.next,a.prev),m.style.opacity=1,e()},200)})}function r(e){e.preventDefault();var t=e.target.nextElementSibling.nextElementSibling,n=t.style.visibility;t.style.visibility=""===n?"visible":"";var a=e.target.nextElementSibling;a.style.visibility=t.style.visibility}function s(e,t){function n(e,t,n){t?(e=e||a(n,t),e.href=t):e&&e.parentNode.removeChild(e)}function a(e,t){var n=document.createElement("link");return n.rel=e,n.href=t,document.head.appendChild(n)}var i=document.head.querySelector("link[rel=next]"),o=document.head.querySelector("link[rel=prev]");n(i,e,"next"),n(o,t,"prev")}function l(e){var t=!e&&"/"===location.pathname||"/"===e;v.className=t?"":"hide"}function d(){f||(f=!0,setTimeout(function(){for(var e=window.innerHeight||document.documentElement.clientHeight,t=0;t=-50&&a.bottom<=e?1:0,a.bottom>e)break}f=!1},200))}var c=document.getElementById("nav"),u=document.getElementById("burger"),m=document.getElementsByTagName("main")[0],v=document.getElementById("hero"),g=m.getElementsByTagName("img"),f=!1;document.body.addEventListener("click",t,!1),window.addEventListener("popstate",function(e){"pushed"===e.state?o(location.pathname):console.log(e)}),window.addEventListener("scroll",d,!1),window.addEventListener("load",d,!1)}(),function(){try{if(window.external.msIsSiteMode()){ext=window.external,ext.msSiteModeCreateJumpList("Navigation");for(var e=document.querySelectorAll("#nav > ul > li > a"),t=e.length-1;t>-1;t--){var n=e[t];ext.msSiteModeAddJumpListItem(n.innerHTML,n.href,"/themes/standard/favicon/favicon.ico")}}}catch(e){}}(),function(){function e(e){var t=i.value;return e.preventDefault(),0===t.trim().length?void i.focus():(a||(a=document.createElement("a"),a.setAttribute("aria-hidden","true"),a.innerHTML="Hidden link used by the site search",a.style.display="none",o.parentNode.appendChild(a)),a.href="/search/"+encodeURIComponent(t),void a.click())}function t(){var e=location.pathname;setInterval(function(){location.pathname!==e&&(e=location.pathname,i.value="")},1e3)}function n(e){s.childNodes.length>0||dataService.sendXhr("/views/keywords.cshtml",function(e){for(var t=JSON.parse(e),n=0;n 2 | @if (Model.Parent != null) 3 | { 4 |

@Model.Title

5 |

@Model.Description

6 | } 7 |
8 | @Helpers.RenderContent(Model) 9 |
10 | 11 | 12 | Edit this page on GitHub -------------------------------------------------------------------------------- /src/views/appcache.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Configuration; 2 | @using System.IO; 3 | @using System.Text; 4 | CACHE MANIFEST 5 | 6 | @{ 7 | Response.ContentType = "text/cache-manifest"; 8 | DateTime date = PageSystem.SetCacheHeaders(Context); 9 | 10 | @("# last modified: " + date.ToString("r")) 11 | 12 | if (Request.IsLocal) 13 | { 14 | Response.StatusCode = 404; 15 | } 16 | } 17 | 18 | @CreateUrlList() 19 | 20 | NETWORK: 21 | * 22 | 23 | @functions { 24 | 25 | string CreateUrlList() 26 | { 27 | StringBuilder sb = new StringBuilder(); 28 | 29 | string themesFolder = Server.MapPath("/themes/" + ConfigurationManager.AppSettings["theme"]); 30 | string pageFolder = Server.MapPath(ConfigurationManager.AppSettings["pageFolder"]); 31 | 32 | List imageExtension = new List { ".gif", ".png", ".jpg" }; 33 | List extensions = new List { ".js", ".css", ".woff", ".ttf", ".eot" }; 34 | 35 | // Pages 36 | sb.AppendLine("# pages"); 37 | sb.AppendLine("/"); 38 | CreatePageList(PageSystem.IndexPage.Children, sb); 39 | 40 | // Theme assets 41 | sb.AppendLine(Environment.NewLine + "# theme assets"); 42 | foreach (string file in Directory.GetFiles(themesFolder, "*.*", SearchOption.AllDirectories)) 43 | { 44 | if (extensions.Contains(Path.GetExtension(file))) 45 | { 46 | string relative = file.Replace(Server.MapPath("~/"), string.Empty).Replace("\"", "/"); 47 | sb.AppendLine(Helpers.Fingerprint("/" + relative)); 48 | } 49 | } 50 | 51 | // Page assets 52 | sb.AppendLine(Environment.NewLine + "# page assets"); 53 | foreach (string file in Directory.EnumerateFiles(pageFolder, "*.*", SearchOption.AllDirectories)) 54 | { 55 | if (imageExtension.Contains(Path.GetExtension(file))) 56 | { 57 | string relative = file.Replace(Path.GetDirectoryName(pageFolder), string.Empty).Replace("\"", "/").ToLowerInvariant(); 58 | sb.AppendLine(Helpers.Fingerprint(relative)); 59 | } 60 | } 61 | 62 | return sb.ToString(); 63 | } 64 | 65 | void CreatePageList(IEnumerable pages, StringBuilder sb) 66 | { 67 | foreach (MarkdownPage page in pages.Where(p => p.ShowInMenu)) 68 | { 69 | sb.AppendLine(Helpers.CreateLink(page)); 70 | CreatePageList(page.Children, sb); 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/views/keywords.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Response.ContentType = "appliation/json"; 3 | string json = "[" + string.Join(",", GetKeywords(PageSystem.IndexPage).Select(k => "\"" + k + "\"")) + "]"; 4 | Response.Write(json); 5 | } 6 | 7 | @functions { 8 | 9 | public static IEnumerable GetKeywords(MarkdownPage parent) 10 | { 11 | var list = new List(); 12 | var pages = Helpers.GetAllPages(parent); 13 | 14 | foreach (MarkdownPage page in pages) 15 | { 16 | var keywords = page.Keywords.Split(',').Select(k => k.Trim()); 17 | 18 | foreach (string keyword in keywords) 19 | { 20 | if (!list.Contains(keyword)) 21 | list.Add(keyword); 22 | } 23 | } 24 | 25 | return list.OrderBy(k => k); 26 | } 27 | } -------------------------------------------------------------------------------- /src/views/opensearch.cshtml: -------------------------------------------------------------------------------- 1 |  2 | @using config = System.Configuration.ConfigurationManager; 3 | @{ 4 | string baseUrl = Request.Url.Scheme + "://" + Request.Url.Authority; 5 | string theme = config.AppSettings["theme"]; 6 | string name = config.AppSettings["name"]; 7 | 8 | Response.ContentType = "application/opensearchdescription+xml"; 9 | } 10 | 11 | @name 12 | @name Search 13 | UTF-8 14 | @baseUrl/themes/@theme/favicon/favicon.ico 15 | 16 | 17 | @baseUrl 18 | -------------------------------------------------------------------------------- /src/views/robots.cshtml: -------------------------------------------------------------------------------- 1 | user-agent: * 2 | crawl-delay: 1 3 | 4 | sitemap: @(Request.Url.Scheme + "://" + Request.Url.Authority)/sitemap.xml 5 | 6 | @{ 7 | Response.ContentType = "text/plain"; 8 | } -------------------------------------------------------------------------------- /src/views/sitemap.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | @WriteUrl(PageSystem.IndexPage) 6 | 7 | 8 | 9 | @helper WriteUrl(MarkdownPage page) 10 | { 11 | 12 | @Helpers.CreateLink(page) 13 | @page.DateModified.ToString("s") 14 | weekly 15 | 16 | foreach (MarkdownPage child in page.Children) 17 | { 18 | @WriteUrl(child) 19 | } 20 | } 21 | 22 | @{ 23 | Response.ContentType = "text/xml"; 24 | } -------------------------------------------------------------------------------- /test/aspnet_compiler.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/vsext-docs/f928283bfb7a0a467e5941d186246beed901f364/test/aspnet_compiler.exe -------------------------------------------------------------------------------- /test/test.ps1: -------------------------------------------------------------------------------- 1 | [cmdletbinding()] 2 | param() 3 | 4 | Write-Host "Running tests..." -ForegroundColor Cyan -NoNewline 5 | 6 | $assemblies = Get-ChildItem ".\output\bin\*.dll" 7 | $folder = Get-ChildItem ".\src\" -Filter pages | where {$_.Attributes -eq 'Directory'} 8 | 9 | foreach($assembly in $assemblies){ 10 | [Reflection.Assembly]::LoadFile($assembly) | Out-Null 11 | } 12 | 13 | $parser = New-Object PageParser $folder.FullName 14 | $page = $parser.Parse() 15 | 16 | if (!$parser.IsValid){ 17 | Write-Host "Fail" -ForegroundColor Red 18 | 19 | foreach($validationMessage in $parser.ValidationMessages){ 20 | [string[]]$params = $validationMessage.Split("|") 21 | $message = $params[0].Trim() 22 | $filename = $params[1].Trim().Replace("\", "/") 23 | 24 | Write-Host "$message in $filename" -ForegroundColor White -BackgroundColor Red 25 | 26 | if (Get-Command Add-AppveyorTest -errorAction SilentlyContinue) 27 | { 28 | Add-AppveyorTest $message -Outcome Failed -FileName $filename 29 | $Host.SetShouldExit(1) 30 | } 31 | } 32 | } 33 | else { 34 | Write-Host "OK" -ForegroundColor Green 35 | } -------------------------------------------------------------------------------- /vsext-docs.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.22609.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "src(14)", "http://localhost:60920", "{B1D5BDCB-EFFF-4087-A66E-4E84519E2F77}" 7 | ProjectSection(WebsiteProperties) = preProject 8 | UseIISExpress = "true" 9 | TargetFrameworkMoniker = ".NETFramework,Version%3Dv4.5.2" 10 | Debug.AspNetCompiler.VirtualPath = "/localhost_65261" 11 | Debug.AspNetCompiler.PhysicalPath = "src\" 12 | Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_65261\" 13 | Debug.AspNetCompiler.Updateable = "true" 14 | Debug.AspNetCompiler.ForceOverwrite = "true" 15 | Debug.AspNetCompiler.FixedNames = "false" 16 | Debug.AspNetCompiler.Debug = "True" 17 | Release.AspNetCompiler.VirtualPath = "/localhost_65261" 18 | Release.AspNetCompiler.PhysicalPath = "src\" 19 | Release.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_65261\" 20 | Release.AspNetCompiler.Updateable = "true" 21 | Release.AspNetCompiler.ForceOverwrite = "true" 22 | Release.AspNetCompiler.FixedNames = "false" 23 | Release.AspNetCompiler.Debug = "False" 24 | SlnRelativePath = "src\" 25 | DefaultWebSiteLanguage = "Visual C#" 26 | EndProjectSection 27 | EndProject 28 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8CB8265B-409B-44AA-8569-20837ECBD349}" 29 | ProjectSection(SolutionItems) = preProject 30 | .gitignore = .gitignore 31 | appveyor.yml = appveyor.yml 32 | README.md = README.md 33 | test\test.ps1 = test\test.ps1 34 | EndProjectSection 35 | EndProject 36 | Global 37 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 38 | Debug|Any CPU = Debug|Any CPU 39 | Release|Any CPU = Release|Any CPU 40 | EndGlobalSection 41 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 42 | {B1D5BDCB-EFFF-4087-A66E-4E84519E2F77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {B1D5BDCB-EFFF-4087-A66E-4E84519E2F77}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {B1D5BDCB-EFFF-4087-A66E-4E84519E2F77}.Release|Any CPU.ActiveCfg = Debug|Any CPU 45 | {B1D5BDCB-EFFF-4087-A66E-4E84519E2F77}.Release|Any CPU.Build.0 = Debug|Any CPU 46 | EndGlobalSection 47 | GlobalSection(SolutionProperties) = preSolution 48 | HideSolutionNode = FALSE 49 | EndGlobalSection 50 | EndGlobal 51 | --------------------------------------------------------------------------------