├── art ├── animation.gif ├── overlay.png ├── settings.png ├── browser-link-menu.png └── browser-link-tooltip.png ├── src ├── Resources │ ├── Icon.png │ └── Preview.png ├── source.extension.ico ├── Properties │ └── AssemblyInfo.cs ├── source.extension.cs ├── Options.cs ├── VSCommandTable.cs ├── VSCommandTable.vsct ├── source.extension.vsixmanifest ├── Commands │ └── EnableSyncCommand.cs ├── BrowserLink │ ├── Overlay.cs │ ├── SyncEngine.cs │ ├── SyncEngine.js │ ├── Overlay.js │ └── _intellisense │ │ ├── browserlink.intellisense.js │ │ └── jquery-1.8.2.intellisense.js ├── packages.config ├── VSPackage.cs ├── source.extension.resx └── BrowserSync.csproj ├── .gitignore ├── .gitattributes ├── LICENSE ├── appveyor.yml ├── BrowserSync.sln ├── README.md └── CONTRIBUTING.md /art/animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/BrowserSync/master/art/animation.gif -------------------------------------------------------------------------------- /art/overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/BrowserSync/master/art/overlay.png -------------------------------------------------------------------------------- /art/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/BrowserSync/master/art/settings.png -------------------------------------------------------------------------------- /src/Resources/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/BrowserSync/master/src/Resources/Icon.png -------------------------------------------------------------------------------- /src/source.extension.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/BrowserSync/master/src/source.extension.ico -------------------------------------------------------------------------------- /art/browser-link-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/BrowserSync/master/art/browser-link-menu.png -------------------------------------------------------------------------------- /src/Resources/Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/BrowserSync/master/src/Resources/Preview.png -------------------------------------------------------------------------------- /art/browser-link-tooltip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/BrowserSync/master/art/browser-link-tooltip.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | packages 2 | node_modules.7z 3 | 4 | # User files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | .vs/ 9 | 10 | # Build results 11 | 12 | [Dd]ebug/ 13 | [Rr]elease/ 14 | x64/ 15 | [Bb]in/ 16 | [Oo]bj/ 17 | 18 | # MSTest test Results 19 | [Tt]est[Rr]esult*/ 20 | [Bb]uild[Ll]og.* 21 | 22 | # NCrunch 23 | *.ncrunchsolution 24 | *.ncrunchproject 25 | _NCrunch_WebCompiler -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015 Mads Kristensen 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /src/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | using BrowserSync; 4 | 5 | [assembly: AssemblyTitle(Vsix.Name)] 6 | [assembly: AssemblyDescription(Vsix.Description)] 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany(Vsix.Author)] 9 | [assembly: AssemblyProduct(Vsix.Name)] 10 | [assembly: AssemblyCopyright(Vsix.Author)] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | 14 | [assembly: ComVisible(false)] 15 | 16 | [assembly: AssemblyVersion(Vsix.Version)] 17 | [assembly: AssemblyFileVersion(Vsix.Version)] -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | os: Visual Studio 2017 2 | 3 | install: 4 | - ps: (new-object Net.WebClient).DownloadString("https://raw.github.com/madskristensen/ExtensionScripts/master/AppVeyor/vsix.ps1") | iex 5 | 6 | before_build: 7 | - ps: Vsix-IncrementVsixVersion | Vsix-UpdateBuildVersion 8 | - ps: Vsix-TokenReplacement src\source.extension.cs 'Version = "([0-9\\.]+)"' 'Version = "{version}"' 9 | 10 | build_script: 11 | - nuget restore -Verbosity quiet 12 | - msbuild /p:configuration=Release /p:DeployExtension=false /p:ZipPackageCompressionLevel=normal /v:m 13 | 14 | after_test: 15 | - ps: Vsix-PushArtifacts | Vsix-PublishToGallery 16 | 17 | before_deploy: 18 | - ps: Vsix-CreateChocolatyPackage -packageId browsersync 19 | 20 | deploy: 21 | - provider: Environment 22 | name: Chocolatey 23 | on: 24 | branch: master 25 | appveyor_repo_commit_message_extended: /\[release\]/ -------------------------------------------------------------------------------- /src/source.extension.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // This file was generated by Extensibility Tools v1.10.211 4 | // 5 | // ------------------------------------------------------------------------------ 6 | namespace BrowserSync 7 | { 8 | static class Vsix 9 | { 10 | public const string Id = "10d9b3af-1338-4c45-bc99-4ec38c3a11fb"; 11 | public const string Name = "Browser Sync"; 12 | public const string Description = @"A Visual Studio extension for ASP.NET projects that leverages Browser Link to synchronize form field entry, page navigation and scroll position."; 13 | public const string Language = "en-US"; 14 | public const string Version = "1.3"; 15 | public const string Author = "Mads Kristensen"; 16 | public const string Tags = "web, Browser Link, ASP.NET"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Options.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using Microsoft.VisualStudio.Shell; 3 | 4 | namespace BrowserSync 5 | { 6 | public class Options : DialogPage 7 | { 8 | [Category("General")] 9 | [DisplayName("Enable form sync")] 10 | [Description("Determines if form fields are automatically synced when typing in them.")] 11 | [DefaultValue(true)] 12 | public bool EnableFormSync { get; set; } = true; 13 | 14 | [Category("General")] 15 | [DisplayName("Enable navigation hotkeys")] 16 | [Description("Determines if the keybord hotkeys (CTRL+ALT+Enter) in the browser should trigger navigational sync.")] 17 | [DefaultValue(true)] 18 | public bool EnableNavigationHotkeys { get; set; } = true; 19 | 20 | [Category("Welcome")] 21 | [DisplayName("Show browser overlay")] 22 | [Description("Shows the overlay in the browsers containing info about the shortcut key.")] 23 | [DefaultValue(true)] 24 | public bool ShowOverlay { get; set; } = true; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/VSCommandTable.cs: -------------------------------------------------------------------------------- 1 | namespace BrowserSync 2 | { 3 | using System; 4 | 5 | /// 6 | /// Helper class that exposes all GUIDs used across VS Package. 7 | /// 8 | internal sealed partial class PackageGuids 9 | { 10 | public const string guidBrowserSyncPackageString = "557a6900-91ba-4097-99d0-c0ad2a12a92c"; 11 | public const string guidBrowserSyncPackageCmdSetString = "44f3346d-7059-4428-9d81-2f16be71e28e"; 12 | public const string guidBrowserLinkCmdSetString = "30947ebe-9147-45f9-96cf-401bfc671a82"; 13 | public static Guid guidBrowserSyncPackage = new Guid(guidBrowserSyncPackageString); 14 | public static Guid guidBrowserSyncPackageCmdSet = new Guid(guidBrowserSyncPackageCmdSetString); 15 | public static Guid guidBrowserLinkCmdSet = new Guid(guidBrowserLinkCmdSetString); 16 | } 17 | /// 18 | /// Helper class that encapsulates all CommandIDs uses across VS Package. 19 | /// 20 | internal sealed partial class PackageIds 21 | { 22 | public const int EnableSyncCommandId = 0x0100; 23 | public const int IDG_BROWSERLINK_COMMANDS = 0x2001; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/VSCommandTable.vsct: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Enable Browser Sync 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /BrowserSync.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27522.3005 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BrowserSync", "src\BrowserSync.csproj", "{0920B3C4-E178-43B5-B316-8C06649A52F8}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FD739EA8-1C86-4079-AFCF-56358DFAA6FA}" 9 | ProjectSection(SolutionItems) = preProject 10 | appveyor.yml = appveyor.yml 11 | README.md = README.md 12 | EndProjectSection 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {0920B3C4-E178-43B5-B316-8C06649A52F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {0920B3C4-E178-43B5-B316-8C06649A52F8}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {0920B3C4-E178-43B5-B316-8C06649A52F8}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {0920B3C4-E178-43B5-B316-8C06649A52F8}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {E8FDE52A-EC4D-42CA-8242-167184507092} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /src/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Browser Sync 6 | A Visual Studio extension for ASP.NET projects that leverages Browser Link to synchronize form field entry, page navigation and scroll position. 7 | https://github.com/madskristensen/BrowserSync 8 | Resources\LICENSE 9 | Resources\Icon.png 10 | Resources\Preview.png 11 | web, Browser Link, ASP.NET 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Commands/EnableSyncCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Design; 3 | using Microsoft.VisualStudio.Shell; 4 | 5 | namespace BrowserSync 6 | { 7 | internal sealed class EnableSyncCommand 8 | { 9 | private readonly Package _package; 10 | 11 | private EnableSyncCommand(Package package, OleMenuCommandService commandService) 12 | { 13 | _package = package; 14 | 15 | var id = new CommandID(PackageGuids.guidBrowserSyncPackageCmdSet, PackageIds.EnableSyncCommandId); 16 | var cmd = new OleMenuCommand(Execute, id); 17 | cmd.BeforeQueryStatus += BeforeQueryStatus; 18 | commandService.AddCommand(cmd); 19 | } 20 | 21 | public static EnableSyncCommand Instance 22 | { 23 | get; 24 | private set; 25 | } 26 | 27 | private IServiceProvider ServiceProvider 28 | { 29 | get { return _package; } 30 | } 31 | 32 | public static void Initialize(Package package, OleMenuCommandService commandService) 33 | { 34 | Instance = new EnableSyncCommand(package, commandService); 35 | } 36 | 37 | private void BeforeQueryStatus(object sender, EventArgs e) 38 | { 39 | var button = (OleMenuCommand)sender; 40 | 41 | button.Checked = VSPackage.Options.EnableFormSync || VSPackage.Options.EnableNavigationHotkeys; 42 | } 43 | 44 | private void Execute(object sender, EventArgs e) 45 | { 46 | var button = (OleMenuCommand)sender; 47 | 48 | VSPackage.Options.EnableFormSync = !button.Checked; 49 | VSPackage.Options.EnableNavigationHotkeys = !button.Checked; 50 | VSPackage.Options.SaveSettingsToStorage(); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/BrowserLink/Overlay.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using System.IO; 3 | using Microsoft.VisualStudio.Web.BrowserLink; 4 | 5 | namespace BrowserSync 6 | { 7 | [Export(typeof(IBrowserLinkExtensionFactory))] 8 | public class OverlayFactory : IBrowserLinkExtensionFactory 9 | { 10 | public BrowserLinkExtension CreateExtensionInstance(BrowserLinkConnection connection) 11 | { 12 | if (VSPackage.Options.ShowOverlay && VSPackage.Options.EnableNavigationHotkeys) 13 | { 14 | return new OverlayExtension(); 15 | } 16 | 17 | return null; 18 | } 19 | 20 | public string GetScript() 21 | { 22 | using (Stream stream = GetType().Assembly.GetManifestResourceStream("BrowserSync.BrowserLink.Overlay.js")) 23 | using (StreamReader reader = new StreamReader(stream)) 24 | { 25 | return reader.ReadToEnd(); 26 | } 27 | } 28 | } 29 | 30 | public class OverlayExtension : BrowserLinkExtension 31 | { 32 | private static bool _showInCurrentVsSession = true; 33 | 34 | public override void OnConnected(BrowserLinkConnection connection) 35 | { 36 | if (_showInCurrentVsSession) 37 | { 38 | Browsers.Client(connection).Invoke("showOverlay"); 39 | base.OnConnected(connection); 40 | } 41 | } 42 | 43 | [BrowserLinkCallback] // This method can be called from JavaScript 44 | public void HideOverlay(bool dontShowAgain) 45 | { 46 | if (dontShowAgain) 47 | { 48 | VSPackage.Options.ShowOverlay = false; 49 | VSPackage.Options.SaveSettingsToStorage(); 50 | } 51 | else 52 | { 53 | //_showInCurrentVsSession = false; 54 | } 55 | 56 | Browsers.All.Invoke("hideOverlay"); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/BrowserLink/SyncEngine.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using System.Linq; 3 | using System.IO; 4 | using Microsoft.VisualStudio.Web.BrowserLink; 5 | 6 | namespace BrowserSync 7 | { 8 | [Export(typeof(IBrowserLinkExtensionFactory))] 9 | public class SyncEngineFactory : IBrowserLinkExtensionFactory 10 | { 11 | public BrowserLinkExtension CreateExtensionInstance(BrowserLinkConnection connection) 12 | { 13 | return new SyncEngineExtension(); 14 | } 15 | 16 | public string GetScript() 17 | { 18 | using (Stream stream = GetType().Assembly.GetManifestResourceStream("BrowserSync.BrowserLink.SyncEngine.js")) 19 | using (StreamReader reader = new StreamReader(stream)) 20 | { 21 | return reader.ReadToEnd(); 22 | } 23 | } 24 | } 25 | 26 | public class SyncEngineExtension : BrowserLinkExtension 27 | { 28 | private BrowserLinkConnection _connection; 29 | public override void OnConnected(BrowserLinkConnection connection) 30 | { 31 | _connection = connection; 32 | base.OnConnected(connection); 33 | } 34 | 35 | [BrowserLinkCallback] // This method can be called from JavaScript 36 | public void Navigate(int xpos, int ypos) 37 | { 38 | if (VSPackage.Options.EnableNavigationHotkeys && Connections.Connections.Any(c => c != _connection)) 39 | { 40 | IClientInvoke others = Browsers.AllExcept(new[] { _connection }); 41 | others.Invoke("syncNavigate", _connection.Url, xpos, ypos); 42 | } 43 | } 44 | 45 | [BrowserLinkCallback] // This method can be called from JavaScript 46 | public void FormSync(string dto) 47 | { 48 | if (VSPackage.Options.EnableFormSync && Connections.Connections.Any(c => c != _connection)) 49 | { 50 | IClientInvoke others = Browsers.AllExcept(new[] { _connection }); 51 | others.Invoke("syncForm", dto); 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/VSPackage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Design; 3 | using System.Runtime.InteropServices; 4 | using System.Threading; 5 | using Microsoft.VisualStudio.Shell; 6 | using Task = System.Threading.Tasks.Task; 7 | 8 | namespace BrowserSync 9 | { 10 | [Guid(PackageGuids.guidBrowserSyncPackageString)] 11 | [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] 12 | [InstalledProductRegistration("#110", "#112", Vsix.Version, IconResourceID = 400)] 13 | [ProvideMenuResource("Menus.ctmenu", 1)] 14 | [ProvideOptionPage(typeof(Options), "Web", Vsix.Name, 101, 102, true, new string[0], ProvidesLocalizedCategoryName = false)] 15 | [ProvideAutoLoad(_activationContextGuid, PackageAutoLoadFlags.BackgroundLoad)] 16 | [ProvideUIContextRule(_activationContextGuid, Vsix.Id, 17 | "WAP | WebSite | ProjectK | DotNetCoreWeb", 18 | new string[] { 19 | "WAP", 20 | "WebSite", 21 | "ProjectK", 22 | "DotNetCoreWeb" 23 | }, 24 | new string[] { 25 | "SolutionHasProjectFlavor:{349C5851-65DF-11DA-9384-00065B846F21}", 26 | "SolutionHasProjectFlavor:{E24C65DC-7377-472B-9ABA-BC803B73C61A}", 27 | "SolutionHasProjectFlavor:{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}", 28 | "SolutionHasProjectCapability:DotNetCoreWeb" 29 | })] 30 | public sealed class VSPackage : AsyncPackage 31 | { 32 | private const string _activationContextGuid = "{4b6c8d76-4918-45ab-9b26-8f246c1773ab}"; 33 | 34 | public static Options Options 35 | { 36 | get; 37 | private set; 38 | } 39 | 40 | protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) 41 | { 42 | var commandService = await GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService; 43 | 44 | await JoinableTaskFactory.SwitchToMainThreadAsync(); 45 | 46 | Options = (Options)GetDialogPage(typeof(Options)); 47 | EnableSyncCommand.Initialize(this, commandService); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/BrowserLink/SyncEngine.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | (function (browserLink, $) { 4 | /// 5 | /// 6 | 7 | function syncNavigation(url, xpos, ypos) { 8 | 9 | if (location.href !== url) { 10 | location.href = url; 11 | } else { 12 | window.scrollTo(xpos, ypos); 13 | } 14 | } 15 | 16 | function syncForm(dto) { 17 | 18 | var data = JSON.parse(dto); 19 | var element = $(data.selector); 20 | 21 | if (element.length) { 22 | var tagName = element[0].tagName; 23 | 24 | if (tagName === "INPUT" || tagName === "TEXTAREA" || tagName === "SELECT") { 25 | 26 | if (element.attr("type") === "checkbox") { 27 | element[0].checked = data.value; 28 | } else { 29 | element.val(data.value); 30 | } 31 | } else if (element[0].contentEditable) { 32 | element.html(data.value); 33 | } 34 | } 35 | } 36 | 37 | function sendSyncNavigate() { 38 | browserLink.invoke("Navigate", window.pageXOffset, window.pageYOffset); 39 | } 40 | 41 | function connectionHandler() { 42 | 43 | document.onkeydown = function (e) { 44 | var evt = e || event; 45 | 46 | if (evt.altKey && evt.ctrlKey && evt.keyCode === 13) { 47 | evt.preventDefault(); 48 | sendSyncNavigate(); 49 | } 50 | }; 51 | 52 | $("body").on("change input", "input, textarea, select, [contenteditable]", function () { 53 | var self = $(this); 54 | var id = self.attr("id"); 55 | var name = self.attr("name"); 56 | var dto = {}; 57 | 58 | // Abort when insecure and the browsers will throw an exception 59 | if (this.type === "file") 60 | return; 61 | 62 | if (id) { 63 | dto.selector = "#" + id; 64 | } else if (name) { 65 | dto.selector = self[0].tagName + "[name='" + name + "']"; 66 | } 67 | 68 | if (dto.selector) { 69 | 70 | if (self.attr("type") === "checkbox") { 71 | dto.value = self.is(":checked"); // jQuery always returns "on" for checkbox.val() 72 | } else if (self.attr("type") === "radio") { 73 | dto.value = [self.val()]; // Radio button value has to be an array 74 | } else { 75 | dto.value = self.val() || self.html(); 76 | } 77 | 78 | browserLink.invoke("FormSync", JSON.stringify(dto)); 79 | } 80 | }); 81 | } 82 | 83 | return { 84 | onConnected: connectionHandler, // Fires automatically when Browser Link connects 85 | syncNavigate: syncNavigation, // Called by SyncEngine.cs 86 | syncForm: syncForm, // Called by SyncEngine.cs 87 | sendSyncNavigate: sendSyncNavigate, 88 | menu: { 89 | displayText: 'Browser Sync', 90 | 'Sync browsers (Ctrl+Alt+Enter)': 'sendSyncNavigate' 91 | } 92 | }; 93 | }); 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Browser Sync 2 | 3 | [](https://ci.appveyor.com/project/madskristensen/browsersync) 4 | 5 | Download the extension at the 6 | [VS Gallery](https://visualstudiogallery.msdn.microsoft.com/5741a548-5179-4a77-ad96-fca71535774d) 7 | or get the 8 | [nightly build](http://vsixgallery.com/extension/10d9b3af-1338-4c45-bc99-4ec38c3a11fb/) 9 | 10 | ------------------------------------------ 11 | 12 | A Visual Studio extension for ASP.NET projects that 13 | leverages Browser Link to synchronize form field entry, 14 | page navigation and scroll position. 15 | 16 |  17 | 18 | ## Feature list 19 | 20 | - Supports **all browsers** and emulators 21 | - Typing in input fields is synced across browsers 22 | - Supports the [Web Essentials Chrome extension](https://chrome.google.com/webstore/detail/web-essentials/mghdcdlpcdiodelbplncnodiiadljhhk) 23 | - Keyboard hotkey to navigate all browsers to same URL 24 | - Keyboard hotkey to synchronize scroll position 25 | - Settings to enable/disable it all 26 | 27 | For Browser Sync to work, make sure that Visual Studio's 28 | Browser Link is up and running. Do that by running an 29 | ASP.NET application from Visual Studio in one or more 30 | browsers. 31 | 32 | Hovering over the Browser Link button on the Standard 33 | toolbar lets you know if Browser Link is connected. 34 | 35 |  36 | 37 | ## Form field sync 38 | This extension registers when typing occurs in these 39 | HTML elements: 40 | 41 | **Input** 42 | ```html 43 | 44 | ``` 45 | 46 | Works for all input types including `range`, `number` and 47 | `password`, `checkbox`, `datetime`, `color` and `radio` 48 | to the extend browsers do. 49 | 50 | The `file` type isn't supported due to browser security 51 | constaints. 52 | 53 | **Textarea** 54 | ```html 55 | 56 | ``` 57 | 58 | **Select** 59 | ```html 60 | 61 | First 62 | Second 63 | 64 | Third 65 | Fourth 66 | 67 | 68 | ``` 69 | 70 | **Multi select** 71 | ```html 72 | 73 | First 74 | Second 75 | Third 76 | 77 | ``` 78 | 79 | **contenteditable="true"** 80 | ```html 81 | 82 | ``` 83 | 84 | > The elements **MUST** have either an _id_ and/or _name_ 85 | > attribute for the sync to work. 86 | 87 | ## Navigation and scroll position 88 | When you have multiple browser windows open onto the 89 | website your building in Visual Studio, it is handy to 90 | be able to navigate all the browsers to the same page on 91 | your site. 92 | 93 | Browser Sync makes that easy. Simply navigate to a page 94 | on your site and hit **CTRL+ALT+Enter** in the browser. 95 | 96 | That will navigate all the other browses to that same page. 97 | 98 | Hit **CTRL+Alt+Enter** again and all browsers will move 99 | to the same scroll position. 100 | 101 | ### Welcome message 102 | The first time after installing this extension, a modal 103 | overlay will be shown in all connected browser as you run 104 | your website. 105 | 106 |  107 | 108 | This is to advertize the otherwise hidden feature of 109 | navigational synchronization which is only available through 110 | a keyboard shortcut in the browser and have no UI of their 111 | own. 112 | 113 | Hitting the **Thanks, got it** button or simply hitting 114 | the **ESC** key will dismiss the modal for the duration of 115 | the current Visual Studio session. It will dismiss the modal 116 | in all the connected browsers. 117 | 118 | By checking the checkbox, the modal will never be shown 119 | again. 120 | 121 | ## Settings 122 | You can disable Browser Sync very easily from the Browser 123 | Link dropdown on the Standard toolbar. 124 | 125 |  126 | 127 | This will disable both the navigational sync using hotkeys 128 | as well as the form field sync. 129 | 130 | Both of those settings can be individually set in the 131 | **Tools -> Options -> Web -> Browser Sync** dialog. 132 | 133 |  134 | 135 | ## License 136 | 137 | [Apache 2.0](LICENSE) -------------------------------------------------------------------------------- /src/BrowserLink/Overlay.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | (function (browserLink, $) { 4 | /// 5 | /// 6 | 7 | var _id = "__browserSync"; 8 | 9 | function showOverlay() { 10 | var overlay = createOverlay(); 11 | document.body.appendChild(overlay); 12 | 13 | // Close the modal on ESC 14 | $(document).on("keyup.browsersync", function (e) { 15 | if (e.keyCode === 27) { 16 | browserLink.invoke("HideOverlay", false); 17 | hideOverlay(); 18 | } 19 | 20 | $(document).off("keyup.browsersync"); 21 | }); 22 | } 23 | 24 | function hideOverlay() { 25 | var overlay = document.getElementById(_id); 26 | 27 | if (overlay) { 28 | overlay.parentNode.removeChild(overlay); 29 | } 30 | } 31 | 32 | function createOverlay() { 33 | 34 | // Blur the background 35 | var overlay = document.createElement("div"); 36 | overlay.id = _id; 37 | 38 | // Create 39 | var modal = document.createElement("aside"); 40 | modal.innerHTML = 41 | "Browser Sync for Visual Studio" + 42 | "" + 43 | "You can now use CTRL + Alt + Enter directly in the browser to synchronize two or more browsers connected to Visual Studio." + 44 | "" + 45 | "Learn more" + 46 | ""; 47 | 48 | overlay.appendChild(modal); 49 | 50 | // Create 51 | var section = document.createElement("section"); 52 | section.innerHTML = 53 | " " + 54 | "Don't show this again"; 55 | 56 | modal.appendChild(section); 57 | 58 | // Create 59 | var button = document.createElement("button"); 60 | button.innerHTML = "Thanks, got it"; 61 | button.onclick = function () { 62 | var checkbox = document.getElementById("__browserSyncHide"); 63 | browserLink.invoke("HideOverlay", checkbox.checked); 64 | hideOverlay(); 65 | }; 66 | 67 | section.appendChild(button); 68 | 69 | // Create
" + 43 | "You can now use CTRL + Alt + Enter directly in the browser to synchronize two or more browsers connected to Visual Studio." + 44 | "" + 45 | "Learn more" + 46 | "