├── LICENSE ├── README.md ├── SECURITY.md ├── TenonAccessibilityChecker.sln ├── TenonAccessibilityChecker ├── ErrorResultSet.cs ├── GlobalSuppressions.cs ├── Guids.cs ├── Intellisense │ ├── browserlink.intellisense.js │ ├── jquery-1.8.2.intellisense.js │ └── jquery-1.8.2.js ├── PkgCmdId.cs ├── Properties │ └── AssemblyInfo.cs ├── Resources │ ├── Images_1.png │ ├── activity-large.gif │ ├── custom.ico │ ├── custom32.ico │ └── custom_16x16.png ├── TaskManager.cs ├── TenonAccessibilityBrowserExtension.cs ├── TenonAccessibilityBrowserExtension.js ├── TenonAccessibilityChecker.csproj ├── TenonAccessibilityChecker.csproj.DotSettings.user ├── TenonAccessibilityChecker.csproj.user ├── TenonAccessibilityChecker.vsct ├── TenonAccessibilityCheckerDialog.xaml ├── TenonAccessibilityCheckerDialog.xaml.cs ├── TenonAccessibilityCheckerPackage.cs ├── TenonModal.xaml ├── TenonModal.xaml.cs ├── contents.Designer.cs ├── contents.resx ├── license.txt ├── packages.config └── source.extension.vsixmanifest └── packages ├── Newtonsoft.Json.6.0.8 ├── Newtonsoft.Json.6.0.8.nupkg ├── lib │ ├── net20 │ │ ├── Newtonsoft.Json.dll │ │ └── Newtonsoft.Json.xml │ ├── net35 │ │ ├── Newtonsoft.Json.dll │ │ └── Newtonsoft.Json.xml │ ├── net40 │ │ ├── Newtonsoft.Json.dll │ │ └── Newtonsoft.Json.xml │ ├── net45 │ │ ├── Newtonsoft.Json.dll │ │ └── Newtonsoft.Json.xml │ ├── netcore45 │ │ ├── Newtonsoft.Json.dll │ │ └── Newtonsoft.Json.xml │ ├── portable-net40+sl5+wp80+win8+wpa81 │ │ ├── Newtonsoft.Json.dll │ │ └── Newtonsoft.Json.xml │ └── portable-net45+wp80+win8+wpa81+aspnetcore50 │ │ ├── Newtonsoft.Json.dll │ │ └── Newtonsoft.Json.xml └── tools │ └── install.ps1 └── repositories.config /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Microsoft 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Accessibility Checker Extension for Visual Studio 3 | 4 | The Tenon HTML Accessibility Checker makes it easier for Visual Studio developers to detect and resolve common accessibility issues with their HTML-based user interfaces. It takes more than static code analysis to create great experiences for people with permanent or situational disabilities. However, there is no reason to ship code with accessibility issues that can be detected automatically. This checker is one of many tools designed to help developers ship better code. 5 | 6 | ## Contribute 7 | 8 | There are many way to contribute to this project: 9 | * Submit new features or fixes (see "Legal stuff" below). 10 | * Submit bugs and verify fixes that are checked in. 11 | * Review source code changes. 12 | * Engage other contributors. 13 | * Comment on the relevant Visual Studio Blog. 14 | * Review the solution in the Visual Studio Gallery. 15 | 16 | 17 | ## Please leverage the code! 18 | 19 | Leverage the code to create new projects. We implemented some interesting features in this solution including: 20 | * Implementing the browser link extension to exchange information between Visual Studio and multiple browsers (so that we can evaluate dynamic HTML rather than raw code) 21 | * Implementing context-specific menu options on the Visual Studio Solution Explorer 22 | * Integrating a RESTful service with Visual Studio 23 | * Integrating results directly into the Visual Studio Error List 24 | 25 | We published this source under an MIT liscense so that you can leverage any of these patterns. 26 | 27 | 28 | ##Documentation 29 | 30 | * You can read more about the Tenon HTML Accessibility Checker on the (Visual Studio blog.)[http://blogs.msdn.com/b/visualstudio/archive/2015/03/03/improving-html-accessibility-with-visual-studio-extensions.aspx] 31 | * You can read about Tenon and the Tenon API at [http://tenon.io] 32 | * You can download the compiled extension directly from the (Visual Studio Gallery)[https://visualstudiogallery.msdn.microsoft.com/0ad320bc-80e4-402a-bf2b-d6c23a3a6730] 33 | 34 | 35 | ## Legal stuff 36 | 37 | If you want to contribute code (please do!) you will need to complete a Contributor License Agreement (CLA). Briefly, this agreement testifies that you are granting us permission to use the submitted change according to the terms of the project's license, and that the work being submitted is under appropriate copyright. 38 | 39 | Please submit a Contributor License Agreement (CLA) before submitting a pull request. You may visit https://cla.microsoft.com to sign digitally. Be sure to include your github user name along with the agreement. Once we have received the signed CLA, we'll review the request. -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /TenonAccessibilityChecker.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30723.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TenonAccessibilityChecker", "TenonAccessibilityChecker\TenonAccessibilityChecker.csproj", "{A1026BAC-968D-41B2-AB76-E160165F13AA}" 7 | EndProject 8 | Global 9 | GlobalSection(TeamFoundationVersionControl) = preSolution 10 | SccNumberOfProjects = 2 11 | SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} 12 | SccTeamFoundationServer = https://twcdot.visualstudio.com/defaultcollection 13 | SccProjectUniqueName0 = TenonAccessibilityChecker\\TenonAccessibilityChecker.csproj 14 | SccProjectName0 = TenonAccessibilityChecker 15 | SccLocalPath0 = TenonAccessibilityChecker 16 | SccLocalPath1 = . 17 | EndGlobalSection 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {A1026BAC-968D-41B2-AB76-E160165F13AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {A1026BAC-968D-41B2-AB76-E160165F13AA}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {A1026BAC-968D-41B2-AB76-E160165F13AA}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {A1026BAC-968D-41B2-AB76-E160165F13AA}.Release|Any CPU.Build.0 = Release|Any CPU 27 | EndGlobalSection 28 | GlobalSection(SolutionProperties) = preSolution 29 | HideSolutionNode = FALSE 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /TenonAccessibilityChecker/ErrorResultSet.cs: -------------------------------------------------------------------------------- 1 | /*------------------------------------------- START OF LICENSE ----------------------------------------- 2 | HTML Accessibility Checker 3 | Copyright (c) Microsoft Corporation 4 | All rights reserved. 5 | MIT License 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | ----------------------------------------------- END OF LICENSE ------------------------------------------*/ 10 | 11 | namespace Microsoft.TenonAccessibilityChecker 12 | { 13 | /// 14 | /// Error List collection class 15 | /// 16 | public class ErrorResultSet 17 | { 18 | public int Certainty { get; set; } 19 | 20 | public string ErrorTitle { get; set; } 21 | 22 | public string ErrorDescription { get; set; } 23 | 24 | public string Line { get; set; } 25 | 26 | public string Column { get; set; } 27 | 28 | public string Referencelink { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /TenonAccessibilityChecker/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. Project-level 3 | // suppressions either have no target or are given a specific target 4 | // and scoped to a namespace, type, member, etc. 5 | // 6 | // To add a suppression to this file, right-click the message in the 7 | // Error List, point to "Suppress Message(s)", and click "In Project 8 | // Suppression File". You do not need to add suppressions to this 9 | // file manually. 10 | 11 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1017:MarkAssembliesWithComVisible")] 12 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Tenon", Scope = "type", Target = "Microsoft.TenonAccessibilityChecker.TenonModal")] 13 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", MessageId = "Tenon", Scope = "resource", Target = "Microsoft.TenonAccessibilityChecker.contents.resources")] 14 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", MessageId = "abb", Scope = "resource", Target = "Microsoft.TenonAccessibilityChecker.contents.resources")] 15 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", MessageId = "api", Scope = "resource", Target = "Microsoft.TenonAccessibilityChecker.contents.resources")] 16 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", MessageId = "php", Scope = "resource", Target = "Microsoft.TenonAccessibilityChecker.contents.resources")] 17 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", MessageId = "tenon", Scope = "resource", Target = "Microsoft.TenonAccessibilityChecker.contents.resources")] 18 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", MessageId = "tenonkey", Scope = "resource", Target = "Microsoft.TenonAccessibilityChecker.contents.resources")] 19 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Tenon")] 20 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Tenon", Scope = "type", Target = "Microsoft.TenonAccessibilityChecker.TenonAccessibilityBrowserExtensionFactory")] 21 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Tenon", Scope = "type", Target = "Microsoft.TenonAccessibilityChecker.TenonAccessibilityBrowserExtension")] 22 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Tenon", Scope = "type", Target = "Microsoft.TenonAccessibilityChecker.TenonAccessibilityCheckerPackage")] 23 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Tenon", Scope = "member", Target = "Microsoft.TenonAccessibilityChecker.TenonAccessibilityCheckerPackage.#TenonStatusCode")] 24 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Tenon", Scope = "member", Target = "Microsoft.TenonAccessibilityChecker.TenonAccessibilityCheckerPackage.#TenonErrorMessage")] 25 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Referencelink", Scope = "member", Target = "Microsoft.TenonAccessibilityChecker.ErrorResultSet.#Referencelink")] 26 | -------------------------------------------------------------------------------- /TenonAccessibilityChecker/Guids.cs: -------------------------------------------------------------------------------- 1 | /*------------------------------------------- START OF LICENSE ----------------------------------------- 2 | HTML Accessibility Checker 3 | Copyright (c) Microsoft Corporation 4 | All rights reserved. 5 | MIT License 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | ----------------------------------------------- END OF LICENSE ------------------------------------------*/ 10 | 11 | // Guids.cs 12 | // MUST match guids.h 13 | using System; 14 | 15 | namespace Microsoft.TenonAccessibilityChecker 16 | { 17 | static class GuidList 18 | { 19 | public const string GuidTenonAccessibilityCheckerPkgString = "3c650eb5-91b6-4984-a205-290d34fd67ae"; 20 | public const string GuidTenonAccessibilityCheckerCmdSetString = "5e621bbb-fc26-4ade-9a02-a533c042267d"; 21 | 22 | public static readonly Guid GuidTenonAccessibilityCheckerCmdSet = new Guid(GuidTenonAccessibilityCheckerCmdSetString); 23 | }; 24 | } -------------------------------------------------------------------------------- /TenonAccessibilityChecker/Intellisense/browserlink.intellisense.js: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | var bl = { 5 | 6 | "invoke": function () { 7 | /// 8 | /// Calls a server method defined in the Visual Studio BrowserLink extension. 9 | /// The name of the server method 10 | /// 11 | /// 12 | /// Calls a server method defined in the Visual Studio BrowserLink extension and sends data. 13 | /// The name of the server method 14 | /// An object to send as a parameter of the server method. 15 | /// 16 | }, 17 | 18 | "invokeAsync": function () { 19 | /// 20 | /// Calls a server method defined in the Visual Studio BrowserLink extension. 21 | /// The name of the server method 22 | /// 23 | /// 24 | /// 25 | /// Calls a server method defined in the Visual Studio BrowserLink extension. 26 | /// The name of the server method 27 | /// An object to send as a parameter of the server method. 28 | /// 29 | /// 30 | }, 31 | 32 | /// The isolated BrowserLink JSON object. 33 | "json": JSON, 34 | 35 | 36 | "log": function () { 37 | /// 38 | /// Logs a message to the browser console. 39 | /// The message to log. 40 | /// 41 | }, 42 | 43 | /// The server-side source mapping data. 44 | "sourceMapping": { 45 | "canMapToSource": function () { 46 | /// 47 | /// Checks if the specified DOM element can be mapped to server source. 48 | /// The DOM element to test against server-side mapping. 49 | /// 50 | /// 51 | }, 52 | 53 | "getCompleteRange": function () { 54 | /// 55 | /// Checks if the specified DOM element can be mapped to server source. 56 | /// The DOM element to test against server-side mapping. 57 | /// 58 | /// 59 | }, 60 | 61 | "getElementAtPosition": function () { 62 | /// 63 | /// Checks if the specified DOM element can be mapped to server source. 64 | /// The absolute path to the source file. 65 | /// The position in the source file. 66 | /// 67 | /// 68 | }, 69 | 70 | "getStartTagRange": function () { 71 | /// 72 | /// Checks if the specified DOM element can be mapped to server source. 73 | /// The DOM element to test against server-side mapping. 74 | /// 75 | /// 76 | }, 77 | 78 | "selectCompleteRange": function () { 79 | /// 80 | /// Checks if the specified DOM element can be mapped to server source. 81 | /// The DOM element to test against server-side mapping. 82 | /// 83 | }, 84 | 85 | "selectStartTagRange": function () { 86 | /// 87 | /// Checks if the specified DOM element can be mapped to server source. 88 | /// The DOM element to test against server-side mapping. 89 | /// 90 | }, 91 | 92 | /// Contains information about the browser and connection. 93 | "initializationData": { 94 | 95 | /// The name of the connected browser. 96 | "appName": "", 97 | 98 | /// The ID of the SignalR connection to Visual Studio. 99 | "requestId": "", 100 | }, 101 | } 102 | }; 103 | 104 | var sourceMap = function () { 105 | return { 106 | /// The absolute file path of the file containing the element on disk. 107 | "sourcePath": "", 108 | 109 | /// The start position of the DOM element in the 'sourcePath' file. 110 | "startPosition": 1, 111 | 112 | /// The length of the DOM element in the 'sourcePath' file. 113 | "length": 1, 114 | } 115 | }; 116 | 117 | var Promise = function () { 118 | return { 119 | "continueWith": function () { 120 | /// 121 | /// Is called when the server replies with a value. 122 | /// 123 | /// 124 | /// The return value from the server. 125 | /// 126 | /// 127 | /// 128 | } 129 | } 130 | } -------------------------------------------------------------------------------- /TenonAccessibilityChecker/PkgCmdId.cs: -------------------------------------------------------------------------------- 1 | /*------------------------------------------- START OF LICENSE ----------------------------------------- 2 | HTML Accessibility Checker 3 | Copyright (c) Microsoft Corporation 4 | All rights reserved. 5 | MIT License 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | ----------------------------------------------- END OF LICENSE ------------------------------------------*/ 10 | 11 | // PkgCmdID.cs 12 | // MUST match PkgCmdID.h 13 | 14 | namespace Microsoft.TenonAccessibilityChecker 15 | { 16 | static class PkgCmdId 17 | { 18 | public const uint CmdidMyTenonCommand = 0x100; 19 | public const uint CmdidMyBrowserExtension = 0x101; 20 | }; 21 | } -------------------------------------------------------------------------------- /TenonAccessibilityChecker/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Resources; 4 | using System.Runtime.CompilerServices; 5 | using System.Runtime.InteropServices; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("TenonAccessibilityChecker")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("Microsoft")] 14 | [assembly: AssemblyProduct("TenonAccessibilityChecker")] 15 | [assembly: AssemblyCopyright("")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | [assembly: ComVisible(false)] 19 | [assembly: CLSCompliant(false)] 20 | [assembly: NeutralResourcesLanguage("en-US")] 21 | 22 | // Version information for an assembly consists of the following four values: 23 | // 24 | // Major Version 25 | // Minor Version 26 | // Build Number 27 | // Revision 28 | // 29 | // You can specify all the values or you can default the Revision and Build Numbers 30 | // by using the '*' as shown below: 31 | 32 | [assembly: AssemblyVersion("0.9.0.0")] 33 | [assembly: AssemblyFileVersion("0.9.*.0")] 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /TenonAccessibilityChecker/Resources/Images_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/AccCheckerExtensionForVS/711309b1f167fe713453345adb60c9b8c624a718/TenonAccessibilityChecker/Resources/Images_1.png -------------------------------------------------------------------------------- /TenonAccessibilityChecker/Resources/activity-large.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/AccCheckerExtensionForVS/711309b1f167fe713453345adb60c9b8c624a718/TenonAccessibilityChecker/Resources/activity-large.gif -------------------------------------------------------------------------------- /TenonAccessibilityChecker/Resources/custom.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/AccCheckerExtensionForVS/711309b1f167fe713453345adb60c9b8c624a718/TenonAccessibilityChecker/Resources/custom.ico -------------------------------------------------------------------------------- /TenonAccessibilityChecker/Resources/custom32.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/AccCheckerExtensionForVS/711309b1f167fe713453345adb60c9b8c624a718/TenonAccessibilityChecker/Resources/custom32.ico -------------------------------------------------------------------------------- /TenonAccessibilityChecker/Resources/custom_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/AccCheckerExtensionForVS/711309b1f167fe713453345adb60c9b8c624a718/TenonAccessibilityChecker/Resources/custom_16x16.png -------------------------------------------------------------------------------- /TenonAccessibilityChecker/TaskManager.cs: -------------------------------------------------------------------------------- 1 | /*------------------------------------------- START OF LICENSE ----------------------------------------- 2 | HTML Accessibility Checker 3 | Copyright (c) Microsoft Corporation 4 | All rights reserved. 5 | MIT License 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | ----------------------------------------------- END OF LICENSE ------------------------------------------*/ 10 | using System; 11 | using Microsoft.VisualStudio.Shell; 12 | using Microsoft.VisualStudio.Shell.Interop; 13 | using System.Globalization; 14 | 15 | namespace Microsoft.TenonAccessibilityChecker 16 | { 17 | /// 18 | /// Helper class to write error to visual studio error list. 19 | /// 20 | public static class TaskManager 21 | { 22 | private static ErrorListProvider ErrorListProvider; 23 | 24 | /// 25 | /// Constructor. 26 | /// 27 | /// 28 | public static void Initialize(IServiceProvider serviceProvider) 29 | { 30 | ErrorListProvider = new ErrorListProvider(serviceProvider); 31 | } 32 | 33 | /// 34 | ///Clear the errors in the Visual Studio error List 35 | /// 36 | public static void ClearErrors() 37 | { 38 | ErrorListProvider.Tasks.Clear(); 39 | } 40 | 41 | /// 42 | /// Focus the visual studio error list 43 | /// 44 | public static void ShowErrorList() 45 | { 46 | ErrorListProvider.BringToFront(); 47 | } 48 | 49 | /// 50 | /// Add error helper method 51 | /// 52 | /// 53 | /// 54 | /// 55 | public static void AddError(ErrorResultSet message, string fileName,IVsHierarchy hierarchyItem) 56 | { 57 | AddTask(message, TaskErrorCategory.Error, fileName, hierarchyItem); 58 | } 59 | 60 | /// 61 | /// Add Warning helper method 62 | /// 63 | /// 64 | /// 65 | /// 66 | public static void AddWarning(ErrorResultSet message, string fileName,IVsHierarchy hierarchyItem) 67 | { 68 | AddTask(message, TaskErrorCategory.Warning, fileName, hierarchyItem); 69 | } 70 | 71 | /// 72 | /// This Method writes errors to visual studio 73 | /// 74 | /// 75 | /// 76 | /// 77 | /// 78 | private static void AddTask(ErrorResultSet message, TaskErrorCategory category, string filedetails, IVsHierarchy hierarchyItem) 79 | { 80 | ErrorListProvider.Tasks.Add(new ErrorTask 81 | { 82 | Category = TaskCategory.User, 83 | ErrorCategory = category, 84 | Text = message.ErrorDescription + " (" +message.Referencelink +")", 85 | HierarchyItem = hierarchyItem, 86 | Column = string.IsNullOrEmpty(message.Column) ? 0 : Int32.Parse(message.Column, CultureInfo.InvariantCulture), 87 | Line = string.IsNullOrEmpty(message.Line) ? 0 : Int32.Parse(message.Line, CultureInfo.InvariantCulture), 88 | Document = filedetails 89 | }); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /TenonAccessibilityChecker/TenonAccessibilityBrowserExtension.cs: -------------------------------------------------------------------------------- 1 | /*------------------------------------------- START OF LICENSE ----------------------------------------- 2 | HTML Accessibility Checker 3 | Copyright (c) Microsoft Corporation 4 | All rights reserved. 5 | MIT License 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | ----------------------------------------------- END OF LICENSE ------------------------------------------*/ 10 | 11 | using System.ComponentModel.Composition; 12 | using System.IO; 13 | using System.Windows; 14 | using Microsoft.VisualStudio.Web.BrowserLink; 15 | using Microsoft.VisualStudio.Shell.Interop; 16 | using Microsoft.VisualStudio.Shell; 17 | 18 | namespace Microsoft.TenonAccessibilityChecker 19 | { 20 | [Export(typeof(IBrowserLinkExtensionFactory))] 21 | public class TenonAccessibilityBrowserExtensionFactory : IBrowserLinkExtensionFactory 22 | { 23 | public BrowserLinkExtension CreateExtensionInstance(BrowserLinkConnection connection) 24 | { 25 | return new TenonAccessibilityBrowserExtension(); 26 | } 27 | 28 | public string GetScript() 29 | { 30 | using (Stream stream = GetType().Assembly.GetManifestResourceStream("Microsoft.TenonAccessibilityChecker.TenonAccessibilityBrowserExtension.js")) 31 | using (StreamReader reader = new StreamReader(stream)) 32 | { 33 | return reader.ReadToEnd(); 34 | } 35 | } 36 | } 37 | 38 | public class TenonAccessibilityBrowserExtension : BrowserLinkExtension 39 | { 40 | private string connectionURL { get; set; } 41 | 42 | private IVsHierarchy projectHierarchy { get; set; } 43 | 44 | public override void OnConnected(BrowserLinkConnection connection) 45 | { 46 | IVsSolution solution = Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(SVsSolution)) as IVsSolution; 47 | 48 | IVsHierarchy hierarchy1 =null; 49 | 50 | if (connection.Project != null) 51 | { 52 | int hr = solution.GetProjectOfUniqueName(connection.Project.UniqueName, out hierarchy1); 53 | } 54 | 55 | projectHierarchy = hierarchy1; 56 | connectionURL = connection.Url.ToString(); 57 | } 58 | 59 | [BrowserLinkCallback] // This method can be called from JavaScript 60 | public void SendText(string message) 61 | { 62 | if (!TenonAccessibilityCheckerPackage.TenonBrowserLinkSetting) 63 | { 64 | TenonModal.InvokedFromBrowser = true; 65 | TenonModal.RenderedContent = message; 66 | 67 | // close all the open TenonAccessibility dialogs 68 | CloseAllWindows(); 69 | 70 | var dialog = new TenonModal(); 71 | 72 | TenonAccessibilityCheckerPackage.ItemFullPath = string.Empty; 73 | TenonAccessibilityCheckerPackage.Hierarchy = null; 74 | dialog.Topmost = true; 75 | TenonAccessibilityCheckerPackage.ItemFullPath = connectionURL; 76 | TenonAccessibilityCheckerPackage.Hierarchy = projectHierarchy; 77 | 78 | //Show the tenon modal browser dialog 79 | dialog.ShowDialog(); 80 | } 81 | } 82 | 83 | /// 84 | /// close the browser extension modal window. 85 | /// 86 | private static void CloseAllWindows() 87 | { 88 | //ensure only one modal dialog is open at a time for that page. 89 | for (int intCounter = Application.Current.Windows.Count - 1; intCounter > 0; intCounter--) 90 | { 91 | var window = Application.Current.Windows[intCounter]; 92 | if (window != null) window.Close(); 93 | } 94 | } 95 | 96 | } 97 | } -------------------------------------------------------------------------------- /TenonAccessibilityChecker/TenonAccessibilityBrowserExtension.js: -------------------------------------------------------------------------------- 1 | /*------------------------------------------- START OF LICENSE ----------------------------------------- 2 | HTML Accessibility Checker 3 | Copyright (c) Microsoft Corporation 4 | All rights reserved. 5 | MIT License 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | ----------------------------------------------- END OF LICENSE ------------------------------------------*/ 10 | 11 | /// JS2085,JS3092 12 | (function (browserLink, $) { 13 | return { 14 | onConnected: function () { // Optional. Is called when a connection is established 15 | var data = document.documentElement.outerHTML; 16 | browserLink.invoke("SendText", data); 17 | } 18 | }; 19 | }); -------------------------------------------------------------------------------- /TenonAccessibilityChecker/TenonAccessibilityChecker.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12.0 5 | 12.0 6 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 7 | SAK 8 | SAK 9 | SAK 10 | SAK 11 | 12 | 13 | 14 | Debug 15 | AnyCPU 16 | 2.0 17 | {A1026BAC-968D-41B2-AB76-E160165F13AA} 18 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | Library 20 | Properties 21 | Microsoft.TenonAccessibilityChecker 22 | TenonAccessibilityChecker 23 | True 24 | Key.snk 25 | v4.5 26 | 27 | 28 | true 29 | full 30 | false 31 | bin\Debug\ 32 | DEBUG;TRACE 33 | prompt 34 | 4 35 | MinimumRecommendedRules.ruleset 36 | 37 | 38 | pdbonly 39 | true 40 | bin\Release\ 41 | TRACE 42 | prompt 43 | 4 44 | true 45 | AllRules.ruleset 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | true 56 | 57 | 58 | true 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | {80CC9F66-E7D8-4DDD-85B6-D9E6CD0E93E2} 86 | 8 87 | 0 88 | 0 89 | primary 90 | False 91 | False 92 | 93 | 94 | {26AD1324-4B7C-44BC-84F8-B86AED45729F} 95 | 10 96 | 0 97 | 0 98 | primary 99 | False 100 | False 101 | 102 | 103 | {1A31287A-4D7D-413E-8E32-3B374931BD89} 104 | 8 105 | 0 106 | 0 107 | primary 108 | False 109 | False 110 | 111 | 112 | {2CE2370E-D744-4936-A090-3FFFE667B0E1} 113 | 9 114 | 0 115 | 0 116 | primary 117 | False 118 | False 119 | 120 | 121 | {1CBA492E-7263-47BB-87FE-639000619B15} 122 | 8 123 | 0 124 | 0 125 | primary 126 | False 127 | False 128 | 129 | 130 | {00020430-0000-0000-C000-000000000046} 131 | 2 132 | 0 133 | 0 134 | primary 135 | False 136 | False 137 | 138 | 139 | 140 | 141 | 142 | 143 | True 144 | True 145 | contents.resx 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | TenonModal.xaml 155 | 156 | 157 | 158 | 159 | true 160 | ResXFileCodeGenerator 161 | contents.Designer.cs 162 | Designer 163 | 164 | 165 | 166 | 167 | 168 | Designer 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | Menus.ctmenu 177 | Designer 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | Always 191 | true 192 | 193 | 194 | Always 195 | true 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | Designer 204 | MSBuild:Compile 205 | 206 | 207 | 208 | true 209 | 210 | 211 | 212 | 219 | -------------------------------------------------------------------------------- /TenonAccessibilityChecker/TenonAccessibilityChecker.csproj.DotSettings.user: -------------------------------------------------------------------------------- 1 |  2 | A1026BAC-968D-41B2-AB76-E160165F13AA/f:contents.resx -------------------------------------------------------------------------------- /TenonAccessibilityChecker/TenonAccessibilityChecker.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Program 5 | C:\Program Files %28x86%29\Microsoft Visual Studio 12.0\Common7\IDE\devenv.exe 6 | /rootsuffix Exp 7 | 8 | 9 | Program 10 | C:\Program Files %28x86%29\Microsoft Visual Studio 12.0\Common7\IDE\devenv.exe 11 | /rootsuffix Exp 12 | 13 | -------------------------------------------------------------------------------- /TenonAccessibilityChecker/TenonAccessibilityChecker.vsct: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 9 | 10 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 33 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 49 | 50 | 57 | 58 | 67 | 68 | 75 | 76 | 77 | 78 | 79 | 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 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /TenonAccessibilityChecker/TenonAccessibilityCheckerDialog.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /TenonAccessibilityChecker/TenonAccessibilityCheckerDialog.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Shapes; 14 | 15 | namespace Microsoft.TenonAccessibilityChecker 16 | { 17 | /// 18 | /// Interaction logic for TenonAccessibilityCheckerDialog.xaml 19 | /// 20 | public partial class TenonAccessibilityCheckerDialog : Window 21 | { 22 | public TenonAccessibilityCheckerDialog() 23 | { 24 | InitializeComponent(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /TenonAccessibilityChecker/TenonAccessibilityCheckerPackage.cs: -------------------------------------------------------------------------------- 1 | /*------------------------------------------- START OF LICENSE ----------------------------------------- 2 | HTML Accessibility Checker 3 | Copyright (c) Microsoft Corporation 4 | All rights reserved. 5 | MIT License 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | ----------------------------------------------- END OF LICENSE ------------------------------------------*/ 10 | 11 | 12 | using System; 13 | using System.Collections.Generic; 14 | using System.ComponentModel.Design; 15 | using System.IO; 16 | using System.Net; 17 | using System.Runtime.InteropServices; 18 | using System.Text; 19 | using EnvDTE; 20 | using Microsoft.VisualStudio; 21 | using Microsoft.VisualStudio.Shell; 22 | using Microsoft.VisualStudio.Shell.Interop; 23 | using Newtonsoft.Json; 24 | using EnvDTE80; 25 | using System.Net.Security; 26 | using System.Security.Cryptography.X509Certificates; 27 | using System.ComponentModel; 28 | using System.Security; 29 | using System.Windows; 30 | 31 | namespace Microsoft.TenonAccessibilityChecker 32 | { 33 | /// 34 | /// This is the class that implements the package exposed by this assembly. 35 | /// 36 | /// The minimum requirement for a class to be considered a valid package for Visual Studio 37 | /// is to implement the IVsPackage interface and register itself with the shell. 38 | /// This package uses the helper classes defined inside the Managed Package Framework (MPF) 39 | /// to do it: it derives from the Package class that provides the implementation of the 40 | /// IVsPackage interface and uses the registration attributes defined in the framework to 41 | /// register itself and its components with the shell. 42 | /// 43 | // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is 44 | // a package. 45 | [PackageRegistration(UseManagedResourcesOnly = true)] 46 | // This attribute is used to register the information needed to show this package 47 | // in the Help/About dialog of Visual Studio. 48 | [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] 49 | 50 | //This is needed to load the package automatically on install. 51 | [ProvideAutoLoad("{f1536ef8-92ec-443c-9ed7-fdadf150da82}")] 52 | // This attribute is needed to let the shell know that this package exposes some menus. 53 | [ProvideMenuResource("Menus.ctmenu", 1)] 54 | [Guid(GuidList.GuidTenonAccessibilityCheckerPkgString)] 55 | public sealed class TenonAccessibilityCheckerPackage : Package 56 | { 57 | ///////////////////////////////////////////////////////////////////////////// 58 | // Overridden Package Implementation 59 | #region Package Members 60 | public static IVsHierarchy Hierarchy { get; set; } 61 | public static string ItemFullPath { get; set; } 62 | 63 | public static string TenonStatusCode { get; set; } 64 | public static string TenonErrorMessage { get; set; } 65 | 66 | public static bool TenonBrowserLinkSetting { get; set; } 67 | 68 | private DTE2 m_applicationObject = null; 69 | private SolutionEvents solutionEvents; 70 | 71 | public DTE2 ApplicationObject 72 | { 73 | get 74 | { 75 | if (m_applicationObject == null) 76 | { 77 | // Get an instance of the currently running Visual Studio IDE 78 | DTE dte = (DTE)GetService(typeof(DTE)); 79 | m_applicationObject = dte as DTE2; 80 | } 81 | return m_applicationObject; 82 | } 83 | } 84 | 85 | /// 86 | /// Initialization of the package; this method is called right after the package is sited, so this is the place 87 | /// where you can put all the initialization code that rely on services provided by VisualStudio. 88 | /// 89 | protected override void Initialize() 90 | { 91 | base.Initialize(); 92 | TaskManager.Initialize(this); 93 | 94 | // Add our command handlers for menu (commands must exist in the .vsct file) 95 | var mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService; 96 | if (null == mcs) return; 97 | 98 | // Create the command for the menu item. 99 | var menuCommandId = new CommandID(GuidList.GuidTenonAccessibilityCheckerCmdSet, (int)PkgCmdId.CmdidMyTenonCommand); 100 | var menuItem = new OleMenuCommand(MenuItemCallback, menuCommandId); 101 | 102 | var menuCommandId1 = new CommandID(GuidList.GuidTenonAccessibilityCheckerCmdSet, (int)PkgCmdId.CmdidMyBrowserExtension); 103 | var menuItem1 = new OleMenuCommand(MenuItemCallback1, menuCommandId1); 104 | 105 | menuItem.BeforeQueryStatus += menuCommand_BeforeQueryStatus; 106 | mcs.AddCommand(menuItem); 107 | 108 | menuItem1.BeforeQueryStatus += menuCommand_BeforeQueryStatus1; 109 | mcs.AddCommand(menuItem1); 110 | 111 | solutionEvents = ApplicationObject.Events.SolutionEvents; 112 | solutionEvents.AfterClosing += new _dispSolutionEvents_AfterClosingEventHandler(SolutionAfterClosing); 113 | } 114 | #endregion 115 | 116 | private void MenuItemCallback1(object sender, EventArgs e) 117 | { 118 | TenonBrowserLinkSetting = !TenonBrowserLinkSetting; 119 | } 120 | public void SolutionAfterClosing() 121 | { 122 | TaskManager.ClearErrors(); 123 | } 124 | 125 | private void menuCommand_BeforeQueryStatus1(object sender, EventArgs e) 126 | { 127 | var menuCommand = sender as OleMenuCommand; 128 | 129 | if (menuCommand != null) 130 | { 131 | menuCommand.Checked = !TenonBrowserLinkSetting; 132 | } 133 | } 134 | 135 | /// 136 | /// Validation to display the "check accessibility with tenon" for certain file type extensions. 137 | /// 138 | /// 139 | /// 140 | private void menuCommand_BeforeQueryStatus(object sender, EventArgs e) 141 | { 142 | var menuCommand = sender as OleMenuCommand; 143 | 144 | if (menuCommand != null) 145 | { 146 | IntPtr hierarchyPtr, selectionContainerPtr; 147 | uint projectItemId; 148 | IVsMultiItemSelect mis; 149 | var monitorSelection = (IVsMonitorSelection)GetGlobalService(typeof(SVsShellMonitorSelection)); 150 | monitorSelection.GetCurrentSelection(out hierarchyPtr, out projectItemId, out mis, out selectionContainerPtr); 151 | 152 | var hierarchy = Marshal.GetTypedObjectForIUnknown(hierarchyPtr, typeof(IVsHierarchy)) as IVsHierarchy; 153 | if (hierarchy != null) 154 | { 155 | object value; 156 | hierarchy.GetProperty(projectItemId, (int)__VSHPROPID.VSHPROPID_Name, out value); 157 | 158 | string extension = value.ToString(); 159 | 160 | if (value != null && 161 | (extension.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase) || 162 | extension.EndsWith(".xhtml", StringComparison.OrdinalIgnoreCase) || 163 | extension.EndsWith(".html", StringComparison.OrdinalIgnoreCase) || 164 | extension.EndsWith(".aspx", StringComparison.OrdinalIgnoreCase) || 165 | extension.EndsWith(".ascx", StringComparison.OrdinalIgnoreCase) || 166 | extension.EndsWith(".asp", StringComparison.OrdinalIgnoreCase) || 167 | extension.EndsWith(".htm", StringComparison.OrdinalIgnoreCase))) 168 | { 169 | menuCommand.Visible = true; 170 | } 171 | else 172 | { 173 | menuCommand.Visible = false; 174 | } 175 | } 176 | } 177 | } 178 | 179 | /// 180 | /// Check if an single item is selected in the project. 181 | /// 182 | /// 183 | /// 184 | /// 185 | public static bool IsSingleProjectItemSelection(out IVsHierarchy hierarchy, out uint itemId) 186 | { 187 | hierarchy = null; 188 | itemId = VSConstants.VSITEMID_NIL; 189 | 190 | var monitorSelection = GetGlobalService(typeof(SVsShellMonitorSelection)) as IVsMonitorSelection; 191 | var solution = GetGlobalService(typeof(SVsSolution)) as IVsSolution; 192 | if (monitorSelection == null || solution == null) 193 | { 194 | return false; 195 | } 196 | 197 | var hierarchyPtr = IntPtr.Zero; 198 | var selectionContainerPtr = IntPtr.Zero; 199 | 200 | try 201 | { 202 | IVsMultiItemSelect multiItemSelect; 203 | var hr = monitorSelection.GetCurrentSelection(out hierarchyPtr, out itemId, out multiItemSelect, out selectionContainerPtr); 204 | 205 | if (ErrorHandler.Failed(hr) || hierarchyPtr == IntPtr.Zero || itemId == VSConstants.VSITEMID_NIL) 206 | { 207 | return false; 208 | } 209 | 210 | // multiple items are selected 211 | if (multiItemSelect != null) return false; 212 | 213 | // there is a hierarchy root node selected, thus it is not a single item inside a project 214 | if (itemId == VSConstants.VSITEMID_ROOT) return false; 215 | 216 | hierarchy = Marshal.GetObjectForIUnknown(hierarchyPtr) as IVsHierarchy; 217 | if (hierarchy == null) return false; 218 | 219 | Guid guidProjectId; 220 | 221 | return !ErrorHandler.Failed(solution.GetGuidOfProject(hierarchy, out guidProjectId)); 222 | } 223 | finally 224 | { 225 | if (selectionContainerPtr != IntPtr.Zero) 226 | { 227 | Marshal.Release(selectionContainerPtr); 228 | } 229 | 230 | if (hierarchyPtr != IntPtr.Zero) 231 | { 232 | Marshal.Release(hierarchyPtr); 233 | } 234 | } 235 | } 236 | 237 | private static ProjectItem GetProjectItemFromHierarchy(IVsHierarchy pHierarchy, uint itemId) 238 | { 239 | object propertyValue; 240 | ErrorHandler.ThrowOnFailure(pHierarchy.GetProperty(itemId, (int)__VSHPROPID.VSHPROPID_ExtObject, out propertyValue)); 241 | 242 | var projectItem = propertyValue as ProjectItem; 243 | if (projectItem == null) return null; 244 | 245 | return projectItem; 246 | } 247 | 248 | 249 | 250 | /// 251 | /// This function is the callback used to execute a command when the a menu item is clicked. 252 | /// See the Initialize method to see how the menu item is associated to this function using 253 | /// the OleMenuCommandService service and the MenuCommand class. 254 | /// 255 | private void MenuItemCallback(object sender, EventArgs e) 256 | { 257 | IVsHierarchy hierarchy; 258 | uint itemid; 259 | 260 | if (!IsSingleProjectItemSelection(out hierarchy, out itemid)) return; 261 | 262 | // ReSharper disable once SuspiciousTypeConversion.Global 263 | var vsProject = (IVsProject)hierarchy; 264 | 265 | string projectFullPath; 266 | if (vsProject != null && ErrorHandler.Failed(vsProject.GetMkDocument(VSConstants.VSITEMID_ROOT, out projectFullPath))) return; 267 | 268 | // get the name of the item 269 | string itemFullPath = null; 270 | if (vsProject != null && ErrorHandler.Failed(vsProject.GetMkDocument(itemid, out itemFullPath))) return; 271 | 272 | var selectedProjectItem = GetProjectItemFromHierarchy(hierarchy, itemid); 273 | 274 | if (selectedProjectItem == null) return; 275 | 276 | if (itemFullPath != null) 277 | { 278 | ItemFullPath = itemFullPath; 279 | Hierarchy = hierarchy; 280 | TenonModal.InvokedFromBrowser = false; 281 | TenonModal customdialog = new TenonModal(); 282 | customdialog.ShowModal(); 283 | } 284 | } 285 | 286 | /// 287 | /// parse the Tenon API response. 288 | /// 289 | /// Response from Tenon API 290 | /// ErrorCollection List 291 | public static IList ParseJson(string jsonOutput) 292 | { 293 | //parse string 294 | dynamic dynObj = JsonConvert.DeserializeObject(jsonOutput); 295 | 296 | if (dynObj != null) 297 | { 298 | TenonStatusCode = (string)dynObj.status; 299 | 300 | if ((string)dynObj.status != contents.TenonApiResponseSuccess) 301 | { 302 | TenonErrorMessage = (string)dynObj.message; 303 | return null; 304 | }; 305 | 306 | return ProcessResults(dynObj); 307 | } 308 | 309 | return null; 310 | } 311 | 312 | /// 313 | /// Process the json result output from the tenon api 314 | /// 315 | /// 316 | /// 317 | private static IList ProcessResults(dynamic dynObj) 318 | { 319 | var eCollectionResult = new List(); 320 | 321 | foreach (var data1 in dynObj.resultSet) 322 | { 323 | var eCollection = new ErrorResultSet 324 | { 325 | Certainty = data1.certainty, 326 | ErrorTitle = (string)data1.errorTitle, 327 | ErrorDescription = WebUtility.HtmlDecode((string)data1.errorDescription), 328 | Column = !string.IsNullOrEmpty(data1.position.ToString()) ? data1.position.column.ToString() : string.Empty, 329 | Line = !string.IsNullOrEmpty(data1.position.ToString()) ? data1.position.line.ToString() : string.Empty, 330 | Referencelink = data1.@ref 331 | }; 332 | 333 | eCollectionResult.Add(eCollection); 334 | } 335 | 336 | TenonErrorMessage = string.Format(contents.TenonAPISuccess, dynObj.resultSummary.issues.totalErrors.ToString(), dynObj.resultSummary.issues.totalWarnings.ToString()); 337 | 338 | return eCollectionResult; 339 | } 340 | 341 | /// 342 | /// call the Tenon API for the provided inputs. 343 | /// 344 | /// 345 | /// 346 | /// 347 | /// 348 | /// 349 | public static string GetJson(string key, string source, string certainty, string level) 350 | { 351 | //replace & to amp; 352 | var strsource = !string.IsNullOrEmpty(source) ? source.Replace("&", "%26") : string.Empty; 353 | 354 | var responseFromServer = string.Empty; 355 | HttpWebRequest req = null; 356 | 357 | try 358 | { 359 | req = (HttpWebRequest)WebRequest.Create(new Uri(contents.TenonService)); 360 | 361 | ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack; 362 | 363 | req.Method = "POST"; 364 | 365 | var encoding = new ASCIIEncoding(); 366 | 367 | var postData = "key=" + key; 368 | postData += ("&src=" + strsource); 369 | postData += ("&inline=" + false); 370 | postData += ("&certainty=" + (certainty == "Errors and Warnings" ? 0 : 80)); 371 | postData += ("&level=" + level); 372 | postData += ("&fragment=" + 0); 373 | postData += ("&importance=" + 1); 374 | postData += ("&priority=" + 0); 375 | postData += ("&store=" + 0); 376 | postData += ("&ref=" + 1); 377 | postData += ("&appID=" + contents.TenonAppId); 378 | 379 | var data = encoding.GetBytes(postData); 380 | 381 | req.ContentType = "application/x-www-form-urlencoded"; 382 | 383 | req.ContentLength = data.Length; 384 | 385 | // Get the request stream. 386 | var dataStream = req.GetRequestStream(); 387 | // Write the data to the request stream. 388 | dataStream.Write(data, 0, data.Length); 389 | // Close the Stream object. 390 | dataStream.Close(); 391 | // Get the response. 392 | var response = req.GetResponse(); 393 | 394 | // Get the stream containing content returned by the server. 395 | dataStream = response.GetResponseStream(); 396 | // Open the stream using a StreamReader for easy access. 397 | if (dataStream != null) 398 | { 399 | var reader = new StreamReader(dataStream); 400 | // Read the content. 401 | responseFromServer = reader.ReadToEnd(); 402 | 403 | // Clean up the streams. 404 | reader.Close(); 405 | //dataStream.Close(); 406 | response.Close(); 407 | 408 | return responseFromServer; 409 | } 410 | 411 | //return responseFromServer; 412 | } 413 | catch (WebException ex) 414 | { 415 | if (ex.Status == WebExceptionStatus.Timeout) 416 | { 417 | TenonErrorMessage = ex.Message.ToString(); 418 | TenonStatusCode = "999"; 419 | } 420 | else 421 | { 422 | TenonErrorMessage = ex.Message.ToString(); 423 | TenonStatusCode = "1000"; 424 | } 425 | throw; 426 | } 427 | catch (Exception ex) 428 | { 429 | TenonErrorMessage = ex.Message.ToString(); 430 | TenonStatusCode = "2000"; 431 | throw; 432 | } 433 | return responseFromServer; 434 | } 435 | 436 | /// 437 | /// Validating the tenon api SSL certificate 438 | /// 439 | /// 440 | /// 441 | /// 442 | /// 443 | /// 444 | private static bool CertificateValidationCallBack( object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) 445 | { 446 | // If the certificate is a valid, signed certificate, return true. 447 | if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None) 448 | { 449 | return true; 450 | } 451 | 452 | // If there are errors in the certificate chain, look at each error to determine the cause. 453 | if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0) 454 | { 455 | if (chain != null && chain.ChainStatus != null) 456 | { 457 | foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus) 458 | { 459 | if ((certificate.Subject == certificate.Issuer) && 460 | (status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot)) 461 | { 462 | // Self-signed certificates with an untrusted root are valid. 463 | continue; 464 | } 465 | else 466 | { 467 | if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError) 468 | { 469 | // If there are any other errors in the certificate chain, the certificate is invalid, 470 | // so the method returns false. 471 | return false; 472 | } 473 | } 474 | } 475 | } 476 | 477 | // When processing reaches this line, the only errors in the certificate chain are 478 | // untrusted root errors for self-signed certificates. These certificates are valid 479 | // for default Exchange server installations, so return true. 480 | return true; 481 | } 482 | else 483 | { 484 | // In all other cases, return false. 485 | return false; 486 | } 487 | } 488 | 489 | 490 | /// 491 | /// Write errors to visual studio error list. 492 | /// 493 | /// 494 | /// 495 | /// 496 | public static void WriteErrors(string itemFullPath, IVsHierarchy hierarchy, IList errors) 497 | { 498 | TaskManager.ClearErrors(); 499 | 500 | var itemFileName = itemFullPath; 501 | 502 | if (errors != null && errors.Count > 0) 503 | { 504 | foreach (var eCollection in errors) 505 | { 506 | //As per Tenon API, certainty greater than equal to 80 is classified as an error. 507 | if (eCollection.Certainty >= 80) 508 | TaskManager.AddError(eCollection, itemFileName, hierarchy); 509 | else 510 | TaskManager.AddWarning(eCollection, itemFileName, hierarchy); 511 | } 512 | } 513 | 514 | //View ErrorList 515 | TaskManager.ShowErrorList(); 516 | } 517 | 518 | } 519 | } 520 | -------------------------------------------------------------------------------- /TenonAccessibilityChecker/TenonModal.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Learn about the 22 | Tenon service and how features like Confidence scores can be used to tune the results (e.g. to find hard to discover issues and eliminate the false positives). 23 | 24 | 25 | Membership is free and registration takes about a minute. 26 | 27 | 28 | 29 | 30 | Register to get a tenon key... 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 |