├── .gitattributes ├── .gitignore ├── Important.txt ├── LICENSE.MD ├── NoteWidget.sln ├── NoteWidgetAddIn ├── .editorconfig ├── AddIn.Ribbon.cs ├── AddIn.cs ├── CCOMStreamWrapper.cs ├── Export │ ├── AbstractExportor.cs │ ├── CustomFileExportor.cs │ ├── ExportFactory.cs │ ├── ExportFormat.cs │ ├── ExportHelper.cs │ ├── HtmlExportor.cs │ ├── IExportor.cs │ ├── MarkdownExportor.cs │ └── OneNoteHostedExportor.cs ├── Markdown │ ├── Extension │ │ ├── ColorSchemeExtension.cs │ │ ├── DiagramExtension.cs │ │ └── HighlightExtension.cs │ ├── HtmlTemplate.cs │ ├── HtmlTemplateBuilder.cs │ ├── ITemplateExtension.cs │ └── ITemplateRender.cs ├── Model │ ├── NodeType.cs │ ├── NoteNode.cs │ ├── NotePage.cs │ └── NotePageInfo.cs ├── NLog.config ├── NoteApplication.cs ├── NoteApplicationContext.cs ├── NoteWidgetAddIn.csproj ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ ├── Settings.settings │ ├── documents.ico │ ├── markdown.png │ ├── markdown_icon.ico │ ├── markdownflag.png │ ├── openfolder.png │ ├── ribbon.xml │ ├── setting.ico │ └── settings.png ├── Resources │ ├── ImageResourceDictionary.xaml │ ├── MarkdownCheatSheet.html │ ├── css │ │ ├── github-markdown-dark.css │ │ ├── github-markdown-light.css │ │ ├── github-markdown.min.css │ │ ├── prism-coy.min.css │ │ ├── prism-dark.min.css │ │ ├── prism-funky.min.css │ │ ├── prism-okaidia.min.css │ │ ├── prism-solarizedlight.min.css │ │ ├── prism-tomorrow.min.css │ │ ├── prism-twilight.min.css │ │ └── prism.css │ └── js │ │ ├── mermaid.min.js │ │ └── prism.js ├── RibbonCommand │ ├── Advanced │ │ ├── AdvancedSettingsDialog.Designer.cs │ │ ├── AdvancedSettingsDialog.cs │ │ ├── AdvancedSettingsDialog.resx │ │ └── WidgetAdvancedSettingsCommand.cs │ ├── Command.cs │ ├── CommandFactory.cs │ ├── Export │ │ ├── ExportToFileCommand.cs │ │ ├── ExportToPathCommand.cs │ │ ├── ExportToPathDialog.Designer.cs │ │ ├── ExportToPathDialog.cs │ │ └── ExportToPathDialog.resx │ ├── Markdown │ │ ├── CheatsheetCommand.cs │ │ ├── PreviewMarkdownCommand.cs │ │ ├── WebBrowserWindow.xaml │ │ └── WebBrowserWindow.xaml.cs │ └── WpfAddInApplication.cs ├── Utils │ ├── EnumDescriptionConverter.cs │ ├── ExceptionAssertion.cs │ ├── Extensions.cs │ ├── MarkdownHelper.cs │ ├── PathHelper.cs │ └── RestrictedNodeTypeAttribute.cs ├── WidgetSettingsManager.cs ├── app.config └── markdown128.png ├── NoteWidgetAddInSetup └── NoteWidgetAddInSetup.vdproj ├── NoteWidgetTests ├── BaseDummyTest.cs ├── BaseInteropTest.cs ├── DummyData │ ├── NotebookHierarchy.xml │ ├── NotebookHierarchy_Expected.xml │ ├── PageHierarchy.xml │ ├── PageWithCursor.xml │ ├── SectionGroupHierarchy.xml │ ├── SectionGroupHierarchy_Expected.xml │ ├── SectionHierarchy.xml │ ├── SectionHierarchy_Expected.xml │ ├── TaggedPage.xml │ ├── {443F89FE-0C2F-41D2-8FCA-B54E1F45349B}{1}{E19524986248993555224420161066687775526316971}.xml │ ├── {443F89FE-0C2F-41D2-8FCA-B54E1F45349B}{1}{E19554024442055462406520137364240064103627971}.xml │ ├── {443F89FE-0C2F-41D2-8FCA-B54E1F45349B}{1}{E19554024442055462406520137364240064166667971}.xml │ ├── {5E3A0919-1331-41D5-B19C-4AE7F96D7626}{1}{E19529340608983392449520151492106384070007221}.xml │ ├── {842240F6-F77A-4421-B2F6-44510E03ABAB}{1}{E19483954550601460158520165992657368372596901}.xml │ ├── {9CA0EF3E-A634-41E8-A1B7-821A01E657E2}{1}{E1949968395446988629731972422109116520132061}.xml │ └── {B75B0FB1-6DB5-4ED2-9C69-4060F8FB7FF8}{1}{E1954863573282337301011917182284793899649511}.xml ├── DummyDataExportTest.cs ├── DummyImpl │ ├── DummyApplication.cs │ ├── DummyWindow.cs │ └── DummyWindows.cs ├── InteropExportTest.cs ├── MarkdownTest.cs ├── NoteApplicationTest.cs ├── NoteWidgetTests.csproj ├── Properties │ ├── Resources.Designer.cs │ ├── Resources.resx │ └── markdown128.png ├── UtilTests.cs └── Utils │ └── DummyData.cs ├── README.MD ├── cheatsheet_snapshot.png ├── commonmark.png ├── diagram-pie.png ├── java-code-highlight.png ├── powershell-copyfile-runas.bat ├── preview_snapshot.png └── template.html /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /Important.txt: -------------------------------------------------------------------------------- 1 | Git remote: 2 | "origin": github.com 3 | "gitee": gitee.com -------------------------------------------------------------------------------- /NoteWidget.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31919.166 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NoteWidgetTests", "NoteWidgetTests\NoteWidgetTests.csproj", "{FB85C7C6-5DB7-4EFB-9BC4-AFFF33C1E3EA}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoteWidgetAddIn", "NoteWidgetAddIn\NoteWidgetAddIn.csproj", "{280104F5-13BA-4193-BFF5-5A5C48261640}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{732EB35D-6A00-4E3C-B1AF-2A7A0ABF10D2}" 11 | ProjectSection(SolutionItems) = preProject 12 | cheatsheet_snapshot.png = cheatsheet_snapshot.png 13 | LICENSE.MD = LICENSE.MD 14 | powershell-copyfile-runas.bat = powershell-copyfile-runas.bat 15 | preview_snapshot.png = preview_snapshot.png 16 | README.MD = README.MD 17 | EndProjectSection 18 | EndProject 19 | Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "NoteWidgetAddIn.Setup", "NoteWidgetAddInSetup\NoteWidgetAddInSetup.vdproj", "{1D540207-035C-40B7-BD5B-48FF023152C2}" 20 | EndProject 21 | Global 22 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 23 | Debug|Any CPU = Debug|Any CPU 24 | Publish|Any CPU = Publish|Any CPU 25 | Release|Any CPU = Release|Any CPU 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {FB85C7C6-5DB7-4EFB-9BC4-AFFF33C1E3EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {FB85C7C6-5DB7-4EFB-9BC4-AFFF33C1E3EA}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {FB85C7C6-5DB7-4EFB-9BC4-AFFF33C1E3EA}.Publish|Any CPU.ActiveCfg = Publish|Any CPU 31 | {FB85C7C6-5DB7-4EFB-9BC4-AFFF33C1E3EA}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {FB85C7C6-5DB7-4EFB-9BC4-AFFF33C1E3EA}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {280104F5-13BA-4193-BFF5-5A5C48261640}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {280104F5-13BA-4193-BFF5-5A5C48261640}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {280104F5-13BA-4193-BFF5-5A5C48261640}.Publish|Any CPU.ActiveCfg = Publish|Any CPU 36 | {280104F5-13BA-4193-BFF5-5A5C48261640}.Publish|Any CPU.Build.0 = Publish|Any CPU 37 | {280104F5-13BA-4193-BFF5-5A5C48261640}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {280104F5-13BA-4193-BFF5-5A5C48261640}.Release|Any CPU.Build.0 = Release|Any CPU 39 | {1D540207-035C-40B7-BD5B-48FF023152C2}.Debug|Any CPU.ActiveCfg = Debug 40 | {1D540207-035C-40B7-BD5B-48FF023152C2}.Debug|Any CPU.Build.0 = Debug 41 | {1D540207-035C-40B7-BD5B-48FF023152C2}.Publish|Any CPU.ActiveCfg = Publish 42 | {1D540207-035C-40B7-BD5B-48FF023152C2}.Release|Any CPU.ActiveCfg = Release 43 | {1D540207-035C-40B7-BD5B-48FF023152C2}.Release|Any CPU.Build.0 = Release 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {6124B423-3309-464C-A107-BD5DD68ED3A3} 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/AddIn.Ribbon.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System.Drawing; 5 | using System.Drawing.Imaging; 6 | using System.IO; 7 | using System.Reflection; 8 | using System.Runtime.InteropServices.ComTypes; 9 | using System.Threading.Tasks; 10 | using Microsoft.Office.Core; 11 | using NoteWidgetAddIn.RibbonCommand; 12 | 13 | #pragma warning disable CS3001 // Argument type is not CLS-compliant 14 | namespace NoteWidgetAddIn 15 | { 16 | public partial class AddIn : IRibbonExtensibility 17 | { 18 | 19 | #region implements IRibbonExtensibility 20 | /// 21 | /// Gets the defined ribbon tab xml string content 22 | /// This method is triggered after OnAddInsUpdate 23 | /// 24 | /// 25 | /// The xml string content which customized ribbon menu items 26 | public string GetCustomUI(string RibbonID) 27 | { 28 | return Properties.Resources.ribbon; 29 | } 30 | #endregion 31 | 32 | #region Custom Ribbon methods 33 | public IStream GetImage(string imageName) 34 | { 35 | var ms = new MemoryStream(); 36 | BindingFlags flags = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; 37 | var b = typeof(Properties.Resources).GetProperty(Path.GetFileNameWithoutExtension(imageName), flags).GetValue(null, null) as Bitmap; 38 | b.Save(ms, ImageFormat.Png); 39 | return new CCOMStreamWrapper(ms); 40 | } 41 | 42 | #endregion 43 | 44 | #region Ribbon Action Commands 45 | /// 46 | /// Export to file 47 | /// 48 | /// 49 | /// 50 | public async Task ExportFileCmd(IRibbonControl control) => await _commandFactory.Run(control.Tag); 51 | 52 | /// 53 | /// Export to hierarchical files 54 | /// 55 | /// 56 | /// 57 | public async Task ExportPathCmd(IRibbonControl control) => await _commandFactory.Run(control.Tag, control.Context); 58 | 59 | /// 60 | /// View current page's markdown content as Html in a new window. 61 | /// 62 | /// 63 | /// 64 | public async Task PreviewMarkdownCmd(IRibbonControl control) => await _commandFactory.Run(); 65 | /// 66 | /// Show markdown cheat sheet window 67 | /// 68 | /// 69 | /// 70 | public async Task MarkdownCheatsheetCmd(IRibbonControl control) => await _commandFactory.Run(); 71 | /// 72 | /// Show advanced settings window 73 | /// 74 | /// 75 | /// 76 | public async Task WidgetAdvancedSettingsCmd(IRibbonControl control) => await _commandFactory.Run(); 77 | 78 | #endregion 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/AddIn.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System; 5 | using System.IO; 6 | using System.Reflection; 7 | using System.Runtime.InteropServices; 8 | using Extensibility; 9 | using NLog; 10 | using NoteWidgetAddIn.RibbonCommand; 11 | 12 | #pragma warning disable CS3008 // Type is not CLS-compliant 13 | #pragma warning disable CS3003 // Type is not CLS-compliant 14 | #pragma warning disable CS3001 // Type is not CLS-compliant 15 | namespace NoteWidgetAddIn 16 | { 17 | [ComVisible(true)] 18 | [Guid("EEE896F2-39B1-4D71-8A54-3EFDFB48BB06"), ProgId("NoteWidget.AddIn")] 19 | public partial class AddIn : IDTExtensibility2 20 | { 21 | private static readonly ILogger _logger = LogManager.GetCurrentClassLogger(); 22 | private CommandFactory _commandFactory; 23 | static AddIn() 24 | { 25 | var nlogConfigPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "NLog.config"); 26 | LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration(nlogConfigPath); 27 | } 28 | 29 | public void OnConnection(object Application, ext_ConnectMode ConnectMode, object AddInInst, ref Array custom) 30 | { 31 | //OneNote window is not ready to use. 32 | _logger.Debug("OnConnection"); 33 | WpfAddInApplication.Current = new WpfAddInApplication(); 34 | } 35 | 36 | public void OnDisconnection(ext_DisconnectMode RemoveMode, ref Array custom) 37 | { 38 | GC.Collect(); 39 | //GC.WaitForPendingFinalizers(); 40 | Environment.Exit(0); 41 | } 42 | 43 | public void OnAddInsUpdate(ref Array custom) 44 | { 45 | } 46 | 47 | public void OnStartupComplete(ref Array custom) 48 | { 49 | //Leave factory instainced here, since from now on OneNote Window is ready to access. 50 | try 51 | { 52 | NoteApplicationContext context = new NoteApplicationContext(); 53 | _commandFactory = new CommandFactory(context); 54 | } 55 | catch (Exception ex) 56 | { 57 | _logger.Error(ex); 58 | } 59 | } 60 | 61 | public void OnBeginShutdown(ref Array custom) 62 | { 63 | _logger.Debug("OnBeginShutdown"); 64 | try 65 | { 66 | _commandFactory = null; 67 | WpfAddInApplication.Current.Shutdown(); 68 | } 69 | catch(Exception ex) 70 | { 71 | _logger.Error(ex); 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/CCOMStreamWrapper.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. 3 | */ 4 | 5 | using System; 6 | using System.Runtime.InteropServices; 7 | using System.Runtime.InteropServices.ComTypes; 8 | 9 | namespace NoteWidgetAddIn 10 | { 11 | class CCOMStreamWrapper : IStream 12 | { 13 | public CCOMStreamWrapper(System.IO.Stream streamWrap) 14 | { 15 | m_stream = streamWrap; 16 | } 17 | 18 | public void Clone(out IStream ppstm) 19 | { 20 | ppstm = new CCOMStreamWrapper(m_stream); 21 | } 22 | 23 | public void Commit(int grfCommitFlags) 24 | { 25 | m_stream.Flush(); 26 | } 27 | 28 | public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten) 29 | { 30 | } 31 | 32 | public void LockRegion(long libOffset, long cb, int dwLockType) 33 | { 34 | throw new System.NotImplementedException(); 35 | } 36 | 37 | public void Read(byte[] pv, int cb, IntPtr pcbRead) 38 | { 39 | Marshal.WriteInt64(pcbRead, m_stream.Read(pv, 0, cb)); 40 | } 41 | 42 | public void Revert() 43 | { 44 | throw new System.NotImplementedException(); 45 | } 46 | 47 | public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition) 48 | { 49 | long posMoveTo = 0; 50 | Marshal.WriteInt64(plibNewPosition, m_stream.Position); 51 | switch (dwOrigin) 52 | { 53 | case 0: 54 | { 55 | /* STREAM_SEEK_SET */ 56 | posMoveTo = dlibMove; 57 | } 58 | break; 59 | case 1: 60 | { 61 | /* STREAM_SEEK_CUR */ 62 | posMoveTo = m_stream.Position + dlibMove; 63 | 64 | } 65 | break; 66 | case 2: 67 | { 68 | /* STREAM_SEEK_END */ 69 | posMoveTo = m_stream.Length + dlibMove; 70 | } 71 | break; 72 | default: 73 | return; 74 | } 75 | if (posMoveTo >= 0 && posMoveTo < m_stream.Length) 76 | { 77 | m_stream.Position = posMoveTo; 78 | Marshal.WriteInt64(plibNewPosition, m_stream.Position); 79 | } 80 | } 81 | 82 | public void SetSize(long libNewSize) 83 | { 84 | m_stream.SetLength(libNewSize); 85 | } 86 | 87 | public void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag) 88 | { 89 | pstatstg = new System.Runtime.InteropServices.ComTypes.STATSTG(); 90 | pstatstg.cbSize = m_stream.Length; 91 | if ((grfStatFlag & 0x0001/* STATFLAG_NONAME */) != 0) 92 | return; 93 | pstatstg.pwcsName = m_stream.ToString(); 94 | } 95 | 96 | public void UnlockRegion(long libOffset, long cb, int dwLockType) 97 | { 98 | throw new System.NotImplementedException(); 99 | } 100 | 101 | public void Write(byte[] pv, int cb, IntPtr pcbWritten) 102 | { 103 | Marshal.WriteInt64(pcbWritten, 0); 104 | m_stream.Write(pv, 0, cb); 105 | Marshal.WriteInt64(pcbWritten, cb); 106 | } 107 | 108 | private System.IO.Stream m_stream; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Export/AbstractExportor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System; 5 | using System.IO; 6 | using System.Text; 7 | using NoteWidgetAddIn.Model; 8 | 9 | namespace NoteWidgetAddIn.Export 10 | { 11 | internal abstract class AbstractExportor : IExportor 12 | { 13 | private NoteApplicationContext _context; 14 | public AbstractExportor(ExportFormat fileFormat) 15 | { 16 | FileFormat = fileFormat; 17 | } 18 | public ExportFormat FileFormat { get; private set; } 19 | protected NoteApplication NoteApp { get; private set; } 20 | 21 | public string FileExtension 22 | { 23 | get 24 | { 25 | return ExportHelper.GetExportFormatFileExtension(FileFormat); 26 | } 27 | } 28 | public void SetContext(NoteApplicationContext context) 29 | { 30 | _context = context; 31 | NoteApp = _context.CreateApplication(); 32 | } 33 | 34 | public abstract void ExportNodeToSingleFile(string nodeID, string filePath); 35 | 36 | protected abstract void CreatePageFile(string pageID, string file); 37 | 38 | public virtual string ExportNodeToHierarchicalFiles(string nodeID, string exportPath, bool createsHierarchicalFolder = true) 39 | { 40 | ExceptionAssertion.ThrowArgumentNullExceptionIfNull(nodeID, nameof(nodeID)); 41 | 42 | if (createsHierarchicalFolder) 43 | { 44 | var rootNode = NoteApp.GetNoteNodeHierarchy(nodeID); 45 | if (rootNode != null) 46 | { 47 | return ExportFileHierarchyRecursively(rootNode, exportPath); 48 | } 49 | return null; 50 | } 51 | else 52 | { 53 | string rootPath; 54 | var rootNode = NoteApp.GetNoteNodeHierarchy(nodeID); 55 | if (rootNode != null) 56 | { 57 | var folderName = $"OneNote_{rootNode.Name}_{DateTime.Now.ToString("yyyyMMddHHmmss")}"; 58 | rootPath = PathHelper.MakeUniqueFolderName(Path.Combine(exportPath, folderName)); 59 | Directory.CreateDirectory(rootPath); 60 | foreach (var node in rootNode.Descendants(n => n.NodeType == NodeType.Page)) 61 | { 62 | var filePath = Path.Combine(rootPath, GetFullPathNodeName(node, '_') + FileExtension); 63 | CreatePageFile(node.ID, PathHelper.MakeUniqueFileName(filePath)); 64 | } 65 | return rootPath; 66 | } 67 | return null; 68 | } 69 | } 70 | 71 | private string ExportFileHierarchyRecursively(NoteNode parentNode, string hierarchyFolderPath) 72 | { 73 | if (parentNode.NodeType == NodeType.Page) 74 | { 75 | var file = Path.Combine(hierarchyFolderPath, PathHelper.MakeValidFileName(parentNode.Name) + FileExtension); 76 | CreatePageFile(parentNode.ID, PathHelper.MakeUniqueFileName(file)); 77 | } 78 | string currentFolderPath; 79 | if (parentNode.NodeType != NodeType.Page || (parentNode.NodeType == NodeType.Page && parentNode.Children.Count > 0)) 80 | { 81 | currentFolderPath = PathHelper.MakeUniqueFolderName(Path.Combine(hierarchyFolderPath, PathHelper.MakeValidFileName(parentNode.Name))); 82 | Directory.CreateDirectory(currentFolderPath); 83 | } 84 | else 85 | { 86 | currentFolderPath = hierarchyFolderPath; 87 | } 88 | foreach (var childNode in parentNode.Children) 89 | { 90 | ExportFileHierarchyRecursively(childNode, currentFolderPath); 91 | } 92 | 93 | return currentFolderPath; 94 | } 95 | 96 | protected string GetFullPathNodeName(NoteNode node, char seperatorChar) 97 | { 98 | var fileNameBuilder = new StringBuilder(); 99 | NoteNode tmp = node; 100 | while (tmp != null) 101 | { 102 | var nodeName = PathHelper.MakeValidFileName(tmp.Name); 103 | if (fileNameBuilder.Length == 0) 104 | { 105 | fileNameBuilder.Append(nodeName); 106 | } 107 | else 108 | { 109 | fileNameBuilder.Insert(0, nodeName + seperatorChar.ToString()); 110 | } 111 | tmp = tmp.Parent; 112 | } 113 | return fileNameBuilder.ToString(); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Export/CustomFileExportor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System.IO; 5 | using NoteWidgetAddIn.Model; 6 | 7 | namespace NoteWidgetAddIn.Export 8 | { 9 | internal abstract class CustomFileExportor : AbstractExportor 10 | { 11 | protected CustomFileExportor(ExportFormat fileFormat) : base(fileFormat) { } 12 | public override void ExportNodeToSingleFile(string nodeID, string filePath) 13 | { 14 | ExceptionAssertion.ThrowArgumentNullExceptionIfNull(nodeID, nameof(nodeID)); 15 | ExceptionAssertion.ThrowArgumentNullExceptionIfNull(filePath, nameof(filePath)); 16 | 17 | var rootNode = NoteApp.GetNoteNodeHierarchy(nodeID); 18 | if (rootNode != null) 19 | { 20 | using (var writer = BeginCreateFile(filePath)) 21 | { 22 | foreach (var node in rootNode.Descendants(n => n.NodeType == NodeType.Page)) 23 | { 24 | WriteFileContent(writer, NoteApp.GetNotePage(node.ID), GetFullPathNodeName(node, '\\')); 25 | } 26 | EndCreateFile(writer); 27 | } 28 | } 29 | } 30 | 31 | protected override void CreatePageFile(string pageID, string file) 32 | { 33 | var page = NoteApp.GetNotePage(pageID); 34 | using (var writer = BeginCreateFile(file)) 35 | { 36 | WriteFileContent(writer, page); 37 | EndCreateFile(writer); 38 | } 39 | } 40 | 41 | protected abstract StreamWriter BeginCreateFile(string file); 42 | protected abstract void WriteFileContent(StreamWriter writer, NotePage page, string title = null); 43 | protected abstract void EndCreateFile(StreamWriter writer); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Export/ExportFactory.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using NoteWidgetAddIn.Export; 5 | 6 | namespace NoteWidgetAddIn 7 | { 8 | public class ExportFactory 9 | { 10 | /// 11 | /// Creates an instance from IExportor 12 | /// 13 | /// 14 | /// 15 | /// 16 | public static IExportor CreateExportor(NoteApplicationContext context,ExportFormat format) 17 | { 18 | IExportor exportor; 19 | if (format == ExportFormat.Markdown) 20 | { 21 | exportor = new MarkdownExportor(format); 22 | } 23 | else if (format == ExportFormat.Html) 24 | { 25 | exportor = new HtmlExportor(format); 26 | } 27 | else 28 | { 29 | exportor = new OneNoteHostedExporter(format); 30 | } 31 | exportor.SetContext(context); 32 | 33 | return exportor; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Export/ExportFormat.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System.ComponentModel; 5 | using Microsoft.Office.Interop.OneNote; 6 | using NoteWidgetAddIn.Model; 7 | 8 | #pragma warning disable CS3016 9 | namespace NoteWidgetAddIn 10 | { 11 | public enum ExportFormat 12 | { 13 | [Description("PDF(*.pdf)")] 14 | [RestrictedNodeType(NodeType.Notebook, NodeType.Section, NodeType.Page)] 15 | PDF = PublishFormat.pfPDF, 16 | [Description("XPS Document(*.xps)")] 17 | [RestrictedNodeType(NodeType.Notebook, NodeType.Section, NodeType.Page)] 18 | XPS = PublishFormat.pfXPS, 19 | [Description("Single File Web Page(*.mht)")] 20 | [RestrictedNodeType(NodeType.Section)] 21 | MHTML = PublishFormat.pfMHTML, 22 | [Description("Microsoft Word XML Document(*.docx)")] 23 | [RestrictedNodeType(NodeType.Section)] 24 | Word = PublishFormat.pfWord, 25 | [Description("Markdown Document(*.md)")] 26 | Markdown = 100, 27 | [Description("Html Document from markdown(*.html)")] 28 | Html = 101 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Export/ExportHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text.RegularExpressions; 9 | using NoteWidgetAddIn.Model; 10 | 11 | namespace NoteWidgetAddIn 12 | { 13 | public class ExportHelper 14 | { 15 | private static IDictionary dictAvailableFormats = new Dictionary(); 16 | public static ExportFormat[] GetAvailableExportFormats(NodeType nodeType) 17 | { 18 | if (!dictAvailableFormats.ContainsKey(nodeType)) 19 | { 20 | var result = new List(); 21 | foreach (var e in (ExportFormat[])Enum.GetValues(typeof(ExportFormat))) 22 | { 23 | var restricted = e.GetRestrictedNodeTypes(); 24 | if (restricted.Length == 0 || (e.GetRestrictedNodeTypes().Contains(nodeType))) 25 | { 26 | result.Add(e); 27 | } 28 | } 29 | dictAvailableFormats.Add(nodeType, result.ToArray()); 30 | } 31 | return dictAvailableFormats[nodeType]; 32 | } 33 | 34 | public static string GetExportFormatExtPattern(ExportFormat format) 35 | { 36 | var desc = format.GetDescription(); 37 | var match = Regex.Match(desc, @"\(([^)]*)\)"); 38 | if (match.Success) 39 | { 40 | return match.Groups[1].Value; 41 | } 42 | throw new InvalidOperationException($"No extension described in {format.GetType()}.{format}"); 43 | } 44 | 45 | public static string GetExportFormatFileExtension(ExportFormat format) 46 | { 47 | return Path.GetExtension(GetExportFormatExtPattern(format)); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Export/HtmlExportor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System.IO; 5 | using NoteWidgetAddIn.Markdown; 6 | using NoteWidgetAddIn.Model; 7 | 8 | namespace NoteWidgetAddIn.Export 9 | { 10 | internal class HtmlExportor : CustomFileExportor 11 | { 12 | public HtmlExportor(ExportFormat fileFormat) : base(fileFormat) 13 | { 14 | 15 | } 16 | protected override StreamWriter BeginCreateFile(string file) 17 | { 18 | var writer = File.CreateText(file); 19 | var title = Path.GetFileNameWithoutExtension(file); 20 | var header = HtmlTemplate.OnlineResourceTemplate.ToHead(title); 21 | writer.WriteLine(header); 22 | writer.Flush(); 23 | return writer; 24 | } 25 | protected override void WriteFileContent(StreamWriter writer, NotePage page, string title = null) 26 | { 27 | if (!string.IsNullOrEmpty(title)) 28 | { 29 | writer.WriteLine("
"); 30 | writer.WriteLine($"

{title}

"); 31 | writer.WriteLine("
"); 32 | } 33 | writer.WriteLine(MarkdownHelper.MarkdownToHtml(page.ContentInnerText)); 34 | writer.WriteLine("

"); 35 | writer.Flush(); 36 | } 37 | 38 | protected override void EndCreateFile(StreamWriter writer) 39 | { 40 | writer.WriteLine(HtmlTemplate.OnlineResourceTemplate.ToFoot()); 41 | writer.Flush(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Export/IExportor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | namespace NoteWidgetAddIn 5 | { 6 | public interface IExportor 7 | { 8 | void SetContext(NoteApplicationContext context); 9 | /// 10 | /// Gets export file format 11 | /// 12 | ExportFormat FileFormat { get; } 13 | /// 14 | /// Export all OneNote pages under specified node to a single file. 15 | /// 16 | /// A Notebook, Section Group, Section or Page ID 17 | /// File name with absolute path 18 | /// the file name of created single file. 19 | void ExportNodeToSingleFile(string nodeID, string filePath); 20 | /// 21 | /// Export OneNote pages under specified node, Each page a file. 22 | /// 23 | /// A Notebook, Section Group, Section or Page ID 24 | /// A absolute path which export file(s) will be created to 25 | /// Creates folder for each Notebook/Section Group/Section 26 | /// the path contains exported files 27 | string ExportNodeToHierarchicalFiles(string nodeID, string exportPath, bool createsHierarchicalFolder = true); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Export/MarkdownExportor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System; 5 | using System.IO; 6 | using NoteWidgetAddIn.Model; 7 | 8 | namespace NoteWidgetAddIn.Export 9 | { 10 | internal class MarkdownExportor : CustomFileExportor 11 | { 12 | public MarkdownExportor(ExportFormat fileFormat) : base(fileFormat) {} 13 | 14 | protected override StreamWriter BeginCreateFile(string file) 15 | { 16 | return File.CreateText(file); 17 | } 18 | protected override void WriteFileContent(StreamWriter writer, NotePage page, string title = null) 19 | { 20 | if (!string.IsNullOrEmpty(title)) 21 | { 22 | writer.WriteLine(new String('-', 50) + " "); 23 | writer.WriteLine(title + " "); 24 | writer.WriteLine(new String('-', 50) + " "); 25 | } 26 | writer.WriteLine(page.ContentInnerText); 27 | writer.WriteLine("\r\n"); 28 | writer.Flush(); 29 | } 30 | 31 | protected override void EndCreateFile(StreamWriter writer) 32 | { 33 | //Nothing to do 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Export/OneNoteHostedExportor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using Microsoft.Office.Interop.OneNote; 5 | 6 | namespace NoteWidgetAddIn.Export 7 | { 8 | internal class OneNoteHostedExporter : AbstractExportor 9 | { 10 | public OneNoteHostedExporter(ExportFormat fileFormat) : base(fileFormat) 11 | { 12 | } 13 | 14 | public override void ExportNodeToSingleFile(string nodeID, string filePath) 15 | { 16 | ExceptionAssertion.ThrowArgumentNullExceptionIfNull(nodeID, nameof(nodeID)); 17 | CreatePageFile(nodeID, filePath); 18 | } 19 | 20 | protected override void CreatePageFile(string nodeID, string file) 21 | { 22 | NoteApp.Publish(nodeID, (PublishFormat)FileFormat, file); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Markdown/Extension/ColorSchemeExtension.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System; 5 | 6 | namespace NoteWidgetAddIn.Markdown.Extension 7 | { 8 | internal class ColorSchemeExtension : ITemplateExtension 9 | { 10 | internal class ColorSchemeRender : ITemplateRender 11 | { 12 | public ColorScheme ColorScheme { get; set; } 13 | public TemplateResourceType ResourceType { get; set; } 14 | public void Render(HtmlTemplate template) 15 | { 16 | string githubCssFileName; 17 | string schemeStyleVar; 18 | if (ColorScheme == ColorScheme.Light) 19 | { 20 | githubCssFileName = "github-markdown-light.css"; 21 | schemeStyleVar = "body{--color-previewwindow-default: #ffffff;}.notewidget-footer{--color-fg-default:#24292f;--color-canvas-default:#ffffff}"; 22 | } 23 | else if (ColorScheme == ColorScheme.Dark) 24 | { 25 | githubCssFileName = "github-markdown-dark.css"; 26 | schemeStyleVar = "body{--color-previewwindow-default: #101010;}.markdown-body code {color: #d63384;font-size: .875em;}.notewidget-footer{--color-fg-default:#c9d1d9;--color-canvas-default:#202020;}::-webkit-scrollbar { width: 10px; height: 10px;}::-webkit-scrollbar-button { background-color: #666; }::-webkit-scrollbar-track { background-color: #202020;}::-webkit-scrollbar-track-piece { background-color: #000;}::-webkit-scrollbar-thumb { height: 50px; background-color: #666; border-radius: 3px;}::-webkit-scrollbar-corner { background-color: #202020;}::-webkit-resizer { background-color: #666;}"; 27 | } 28 | else //Use System Settings 29 | { 30 | githubCssFileName = "github-markdown.min.css"; 31 | schemeStyleVar = "@media (prefers-color-scheme: dark) {body{--color-previewwindow-default: #202020;}.markdown-body code {color: #d63384;font-size: .875em;}.notewidget-footer{--color-fg-default:#c9d1d9;--color-canvas-default:#0d1117;}::-webkit-scrollbar { width: 10px; height: 10px;}::-webkit-scrollbar-button { background-color: #666; }::-webkit-scrollbar-track { background-color: #202020;}::-webkit-scrollbar-track-piece { background-color: #000;}::-webkit-scrollbar-thumb { height: 50px; background-color: #666; border-radius: 3px;}::-webkit-scrollbar-corner { background-color: #202020;}::-webkit-resizer { background-color: #666;}}@media(prefers-color-scheme: light){body{--color-previewwindow-default: #ffffff;}.notewidget-footer{--color-fg-default:#24292f;--color-canvas-default:#ffffff}}"; 32 | } 33 | string schemeStyle = ""; 34 | 35 | string gitHubCssUrl; 36 | if (ResourceType == TemplateResourceType.Local) 37 | { 38 | gitHubCssUrl = $"http://notewidget-vitual-host/resources/css/{githubCssFileName}"; 39 | } 40 | else 41 | { 42 | gitHubCssUrl = $"https://cdn.jsdelivr.net/npm/github-markdown-css/{githubCssFileName}"; 43 | } 44 | template.Stylesheets.Add($""); 45 | template.Stylesheets.Add(schemeStyle); 46 | } 47 | } 48 | public void Setup(HtmlTemplateBuilder builder, TemplateResourceType resourceType) 49 | { 50 | var scheme = Enum.TryParse(Properties.Settings.Default.Markdown_ColorScheme ?? String.Empty, out var result) ? result : ColorScheme.System; 51 | var render = new ColorSchemeRender { ColorScheme = scheme, ResourceType = resourceType }; 52 | builder.Renders.Add(render); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Markdown/Extension/DiagramExtension.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System; 5 | 6 | namespace NoteWidgetAddIn.Markdown.Extension 7 | { 8 | internal class DiagramExtension : ITemplateExtension 9 | { 10 | internal class DiagramRender : ITemplateRender 11 | { 12 | public ColorScheme ColorScheme { get; set; } 13 | public TemplateResourceType ResourceType { get; set; } 14 | public void Render(HtmlTemplate template) 15 | { 16 | string mermaidJsUrl; 17 | if (ResourceType == TemplateResourceType.Local) 18 | { 19 | mermaidJsUrl = "http://notewidget-vitual-host/resources/js/mermaid.min.js"; 20 | } 21 | else 22 | { 23 | mermaidJsUrl = "https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"; 24 | } 25 | template.PostScripts.Add($""); 26 | 27 | if (ColorScheme == ColorScheme.Light) 28 | { 29 | template.PostScripts.Add(""); 30 | } 31 | else if (ColorScheme == ColorScheme.Dark) 32 | { 33 | template.PostScripts.Add(""); 34 | } 35 | else //Use System Settings 36 | { 37 | template.PostScripts.Add(""); 38 | } 39 | } 40 | } 41 | public void Setup(HtmlTemplateBuilder builder, TemplateResourceType resourceType) 42 | { 43 | var scheme = Enum.TryParse(Properties.Settings.Default.Markdown_ColorScheme ?? String.Empty, out var result) ? result : ColorScheme.System; 44 | builder.Renders.Add(new DiagramRender { ResourceType = resourceType, ColorScheme = scheme }); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Markdown/Extension/HighlightExtension.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System; 5 | 6 | namespace NoteWidgetAddIn.Markdown.Extension 7 | { 8 | internal class HighlightExtension : ITemplateExtension 9 | { 10 | internal class HighlightTemplateRender : ITemplateRender 11 | { 12 | public HighlightTheme HighlightTheme { get; set; } 13 | public TemplateResourceType ResourceType { get; set; } 14 | public void Render(HtmlTemplate template) 15 | { 16 | string highlightCssFileName; 17 | if (HighlightTheme == HighlightTheme.Default) 18 | { 19 | highlightCssFileName = "prism.css"; 20 | } 21 | else 22 | { 23 | highlightCssFileName = $"prism-{HighlightTheme.ToString().ToLower()}.min.css"; 24 | } 25 | if (ResourceType == TemplateResourceType.Local) 26 | { 27 | template.Stylesheets.Add($""); 28 | template.PostScripts.Add(""); 29 | } 30 | else 31 | { 32 | template.Stylesheets.Add($""); 33 | template.PostScripts.Add(""); 34 | template.PostScripts.Add(""); 35 | } 36 | } 37 | } 38 | public void Setup(HtmlTemplateBuilder builder, TemplateResourceType resourceType) 39 | { 40 | var theme = Enum.TryParse(Properties.Settings.Default.Markdown_HighlightTheme ?? String.Empty, out var result) ? result : HighlightTheme.Default; 41 | var render = new HighlightTemplateRender { HighlightTheme = theme, ResourceType = resourceType }; 42 | builder.Renders.Add(render); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Markdown/HtmlTemplate.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Web; 7 | 8 | namespace NoteWidgetAddIn.Markdown 9 | { 10 | public class HtmlTemplate 11 | { 12 | static HtmlTemplate() 13 | { 14 | BuildDefaultTemplates(); 15 | } 16 | #region consts 17 | private const string HTML_HEAD = @" 18 | 19 | 20 | 21 | 22 | {{HeadContent}} 23 | 24 | {{Title}} 25 | 26 | 27 |
28 |
"; 29 | private const string HTML_FOOT = @" 30 |
31 |
32 |

{{footer}}

33 |
34 |
35 | {{FootContent}} 36 | 37 | 38 | "; 39 | #endregion 40 | public static HtmlTemplate LocalResourceTemplate { get; private set; } 41 | public static HtmlTemplate OnlineResourceTemplate { get; private set; } 42 | public static void BuildDefaultTemplates() 43 | { 44 | var templateBuilder = HtmlTemplateBuilder.CreateDefaultHtmlTemplateBuilder(TemplateResourceType.Local); 45 | LocalResourceTemplate = templateBuilder.Build(); 46 | templateBuilder = HtmlTemplateBuilder.CreateDefaultHtmlTemplateBuilder(TemplateResourceType.Online); 47 | OnlineResourceTemplate = templateBuilder.Build(); 48 | } 49 | 50 | public IList Stylesheets { get; } 51 | public IList Scripts { get; } 52 | public IList PostScripts { get; } 53 | public HtmlTemplate() 54 | { 55 | Stylesheets = new List(); 56 | Scripts = new List(); 57 | PostScripts = new List(); 58 | } 59 | public string ToHead(string title) 60 | { 61 | StringBuilder stringBuilder = new StringBuilder(); 62 | foreach(var style in Stylesheets) 63 | { 64 | stringBuilder.AppendLine($"\t\t{style}"); 65 | } 66 | 67 | foreach(var script in Scripts) 68 | { 69 | stringBuilder.AppendLine($"\t\t{script}"); 70 | } 71 | 72 | return HTML_HEAD.Replace("{{HeadContent}}", stringBuilder.ToString()).Replace("{{Title}}", HttpUtility.HtmlDecode(title ?? string.Empty)); 73 | } 74 | public string ToFoot(string footer = null) 75 | { 76 | StringBuilder stringBuilder = new StringBuilder(); 77 | foreach (var script in PostScripts) 78 | { 79 | stringBuilder.AppendLine($"\t\t{script}"); 80 | } 81 | return HTML_FOOT.Replace("{{footer}}", footer ?? string.Empty).Replace("{{FootContent}}", stringBuilder.ToString()); 82 | } 83 | 84 | public string ToHtml(string title, string htmlBodyContent, string footer = null) 85 | { 86 | return ToHead(title) + htmlBodyContent + ToFoot(footer); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Markdown/HtmlTemplateBuilder.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using NoteWidgetAddIn.Markdown.Extension; 7 | 8 | namespace NoteWidgetAddIn.Markdown 9 | { 10 | public class HtmlTemplateBuilder 11 | { 12 | private HtmlTemplateBuilder(TemplateResourceType resourceType) 13 | { 14 | _extensions = new List(); 15 | Renders = new List(); 16 | ResourceType = resourceType; 17 | } 18 | public TemplateResourceType ResourceType { get; } 19 | private List _extensions; 20 | public IEnumerable Extensions 21 | { 22 | get 23 | { 24 | return _extensions; 25 | } 26 | } 27 | public HtmlTemplateBuilder AddExtensionIfNotExists() where T: ITemplateExtension, new() 28 | { 29 | if (!Contains()) 30 | { 31 | _extensions.Add(new T()); 32 | } 33 | return this; 34 | } 35 | 36 | public bool Contains() 37 | { 38 | return _extensions.Any(e => e is T); 39 | } 40 | 41 | public static HtmlTemplateBuilder CreateDefaultHtmlTemplateBuilder(TemplateResourceType resourceType) 42 | { 43 | return new HtmlTemplateBuilder(resourceType) 44 | .AddExtensionIfNotExists() 45 | .AddExtensionIfNotExists() 46 | .AddExtensionIfNotExists(); 47 | } 48 | 49 | public List Renders { get; } 50 | 51 | public HtmlTemplate Build() 52 | { 53 | foreach(var extension in Extensions) 54 | { 55 | extension.Setup(this, ResourceType); 56 | } 57 | var template = new HtmlTemplate(); 58 | foreach(var render in Renders) 59 | { 60 | render.Render(template); 61 | } 62 | return template; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Markdown/ITemplateExtension.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System.ComponentModel; 5 | 6 | namespace NoteWidgetAddIn.Markdown 7 | { 8 | public enum TemplateResourceType 9 | { 10 | Local, 11 | Online 12 | } 13 | public enum ColorScheme 14 | { 15 | /// 16 | /// Follow system theme. Default theme. 17 | /// 18 | [Description("Use system setting")] 19 | System = 0, 20 | [Description("Light")] 21 | Light = 1, 22 | [Description("Dark")] 23 | Dark = 2 24 | } 25 | /// 26 | /// Source code hight theme 27 | /// 28 | public enum HighlightTheme 29 | { 30 | Default, 31 | Coy, 32 | Dark, 33 | Funky, 34 | Okaidia, 35 | Solarizedlight, 36 | Tomorrow, 37 | Twilight 38 | } 39 | public interface ITemplateExtension 40 | { 41 | void Setup(HtmlTemplateBuilder builder, TemplateResourceType resourceType); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Markdown/ITemplateRender.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | namespace NoteWidgetAddIn.Markdown 5 | { 6 | public interface ITemplateRender 7 | { 8 | void Render(HtmlTemplate template); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Model/NodeType.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | namespace NoteWidgetAddIn.Model 5 | { 6 | public enum NodeType 7 | { 8 | Notebook, 9 | SectionGroup, 10 | Section, 11 | Page 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Model/NotePageInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using Microsoft.Office.Interop.OneNote; 5 | 6 | namespace NoteWidgetAddIn.Model 7 | { 8 | public enum NotePageInfo 9 | { 10 | /// 11 | /// Returns only basic page content, without selection markup, file types for binary data objects and binary data objects. 12 | /// This is the standard value to pass. 13 | /// Value = 0 14 | /// 15 | Basic = PageInfo.piBasic, 16 | /// 17 | /// Returns page content with no selection markup, but with all binary data. 18 | /// Value = 1 19 | /// 20 | BinaryData = PageInfo.piBinaryData, 21 | /// 22 | /// Returns page content with selection markup, but no binary data. 23 | /// Value = 2 24 | /// 25 | Selection = PageInfo.piSelection, 26 | /// 27 | /// Returns page content with selection markup and all binary data. 28 | /// Value = 3 29 | /// 30 | BinaryDataSelection = PageInfo.piBinaryDataSelection, 31 | /// 32 | /// Returns page content with file type info for binary data objects. 33 | /// Value = 4 34 | /// 35 | FileType = PageInfo.piFileType, 36 | /// 37 | /// Returns page content with file type info for binary data objects and binary data objects 38 | /// Value = 5 39 | /// 40 | BinaryDataFileType = PageInfo.piBinaryDataFileType, 41 | /// 42 | /// Returns page content with selection markup and file type info for binary data. 43 | /// Value = 6 44 | /// 45 | SelectionFileType = PageInfo.piSelectionFileType, 46 | /// 47 | /// Returns all page content. 48 | /// Value = 7 49 | /// 50 | All = PageInfo.piAll, 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/NLog.config: -------------------------------------------------------------------------------- 1 |  2 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/NoteApplication.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Xml.Linq; 8 | using Microsoft.Office.Interop.OneNote; 9 | using NLog; 10 | using NoteWidgetAddIn.Model; 11 | 12 | #pragma warning disable CS3001 // Type is not CLS-compliant 13 | namespace NoteWidgetAddIn 14 | { 15 | public sealed class NoteApplication : IDisposable 16 | { 17 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); 18 | #region Helpers 19 | private class SimpleWin32Window : System.Windows.Forms.IWin32Window 20 | { 21 | public SimpleWin32Window(long windowHandle) 22 | { 23 | Handle = new IntPtr(windowHandle); 24 | } 25 | public IntPtr Handle { get; } 26 | } 27 | 28 | public static System.Windows.Forms.IWin32Window CreateWin32Window(long handle) 29 | { 30 | return new SimpleWin32Window(handle); 31 | } 32 | #endregion 33 | 34 | private readonly NoteApplicationContext _context; 35 | private IApplication _application; 36 | internal NoteApplication(NoteApplicationContext context) 37 | { 38 | _context = context; 39 | _application = context.ResisteredApplicationType == null? new Application() : 40 | (IApplication)Activator.CreateInstance(_context.ResisteredApplicationType); 41 | } 42 | 43 | public string CurrentNotebookID => _application?.Windows.CurrentWindow?.CurrentNotebookId; 44 | public string CurrentSectionGroupID => _application?.Windows.CurrentWindow?.CurrentSectionGroupId; 45 | public string CurrentSectionID => _application?.Windows.CurrentWindow?.CurrentSectionId; 46 | public string CurrentPageID => _application?.Windows.CurrentWindow?.CurrentPageId; 47 | public System.Windows.Forms.IWin32Window CreateCurrentWin32Window() => CreateWin32Window((long)(_application?.Windows.CurrentWindow?.WindowHandle ?? 0)); 48 | 49 | #region NoteNode 50 | public ICollection GetAllNotebookHierarchy() 51 | { 52 | var xmlOut = GetHierarchy(null, HierarchyScope.hsPages); 53 | 54 | if (!string.IsNullOrEmpty(xmlOut)) 55 | { 56 | return NoteNode.HierarchicalNodesFrom(xmlOut); 57 | } 58 | 59 | return new List(); 60 | } 61 | public NoteNode GetNoteNodeHierarchy(string startNodeId) 62 | { 63 | if (string.IsNullOrEmpty(startNodeId)) 64 | throw new ArgumentNullException("startNodeId"); 65 | 66 | _application.GetHierarchy(startNodeId, HierarchyScope.hsPages, out var xmlOut); 67 | 68 | if (!string.IsNullOrEmpty(xmlOut)) 69 | { 70 | return NoteNode.HierarchicalNodesFrom(xmlOut).FirstOrDefault(); 71 | } 72 | return null; 73 | } 74 | #endregion 75 | 76 | #region Hierarchy 77 | /// 78 | /// Returns xml hierarchy for specified startNodeID. Returns all notebooks hierarchy if startNodeID is null. 79 | /// 80 | /// An ID of a Notebook/Section Group/Section/Page. 81 | /// 82 | /// 83 | public string GetHierarchy(string startNodeID, HierarchyScope scope) 84 | { 85 | _application.GetHierarchy(startNodeID, scope, out var xmlOut); 86 | return xmlOut; 87 | } 88 | #endregion 89 | 90 | #region Page Content 91 | public void NewMarkdownPage() 92 | { 93 | var sectionID = CurrentSectionID; 94 | if (sectionID == null) 95 | { 96 | throw new InvalidOperationException("No Section is currently viewed."); 97 | } 98 | _application.CreateNewPage(sectionID, out var newPageID); 99 | var page = GetNotePage(newPageID); 100 | page.SetMarkdownFlag(); 101 | UpdatePage(page); 102 | } 103 | public NotePage GetCurrentNotePage(NotePageInfo pageInfo = NotePageInfo.All) 104 | { 105 | return GetNotePage(CurrentPageID, pageInfo); 106 | } 107 | public NotePage GetNotePage(string pageID, NotePageInfo pageInfo = NotePageInfo.All) 108 | { 109 | ExceptionAssertion.ThrowArgumentNullExceptionIfNull(pageID, nameof(pageID)); 110 | _application.GetPageContent(pageID, out var xmlOut, (PageInfo)pageInfo, XMLSchema.xs2013); 111 | if (!string.IsNullOrEmpty(xmlOut)) 112 | { 113 | return new NotePage(XElement.Parse(xmlOut)); 114 | } 115 | return null; 116 | } 117 | 118 | public void DeletePageContent(string pageID, string objectID) 119 | { 120 | _application.DeletePageContent(pageID, objectID); 121 | } 122 | 123 | public void UpdatePage(NotePage page) 124 | { 125 | _application.UpdatePageContent(page.Root.ToString(SaveOptions.DisableFormatting), DateTime.MinValue, XMLSchema.xs2013, true); 126 | } 127 | #endregion 128 | 129 | #region Export 130 | public void Publish(string nodeID, PublishFormat format, string filePath) 131 | { 132 | ExceptionAssertion.ThrowArgumentNullExceptionIfNull(nodeID, nameof(nodeID)); 133 | ExceptionAssertion.ThrowArgumentNullExceptionIfNull(filePath, nameof(filePath)); 134 | _application.Publish(nodeID, filePath, format); 135 | } 136 | #endregion 137 | 138 | #region IDisposable 139 | public void Dispose() 140 | { 141 | _application = null; 142 | Logger.Debug($"NoteApplication Disposed. Hash: {this.GetHashCode()}"); 143 | } 144 | #endregion 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/NoteApplicationContext.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System; 5 | using Microsoft.Office.Interop.OneNote; 6 | 7 | namespace NoteWidgetAddIn 8 | { 9 | public class NoteApplicationContext 10 | { 11 | public NoteApplicationContext() 12 | { 13 | ResisteredApplicationType = null; 14 | } 15 | /// 16 | /// Construct context with specified type. Usually for testing purpose 17 | /// 18 | /// A type inherit from IApplication 19 | /// 20 | public NoteApplicationContext(Type type) 21 | { 22 | ExceptionAssertion.ThrowArgumentNullExceptionIfNull(type, nameof(type)); 23 | if (!typeof(IApplication).IsAssignableFrom(type)) 24 | { 25 | throw new InvalidOperationException($"{nameof(type)} '{type.FullName}' must be derived from Microsoft.Office.Interop.OneNote.IApplication"); 26 | } 27 | if (type.IsInterface || type.IsAbstract) 28 | { 29 | throw new InvalidOperationException($"{nameof(type)} cannot be interface or abstract."); 30 | } 31 | ResisteredApplicationType = type; 32 | } 33 | public Type ResisteredApplicationType { get;} 34 | public NoteApplication CreateApplication() 35 | { 36 | return new NoteApplication(this); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Efrey Kong. All Rights Reserved. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | using System; 5 | using System.Reflection; 6 | using System.Runtime.CompilerServices; 7 | using System.Runtime.InteropServices; 8 | 9 | // General Information about an assembly is controlled through the following 10 | // set of attributes. Change these attribute values to modify the information 11 | // associated with an assembly. 12 | [assembly: AssemblyTitle("NoteWidgetAddIn")] 13 | [assembly: AssemblyDescription("OneNote Widget AddIn")] 14 | [assembly: AssemblyConfiguration("")] 15 | [assembly: AssemblyCompany("EKStudio")] 16 | [assembly: AssemblyProduct("NoteWidgetAddIn")] 17 | [assembly: AssemblyCopyright("Copyright \u00a9 EKStudio. 2021")] 18 | [assembly: AssemblyTrademark("")] 19 | [assembly: AssemblyCulture("")] 20 | 21 | // Setting ComVisible to false makes the types in this assembly not visible 22 | // to COM components. If you need to access a type in this assembly from 23 | // COM, set the ComVisible attribute to true on that type. 24 | [assembly: ComVisible(true)] 25 | [assembly: CLSCompliant(true)] 26 | [assembly: InternalsVisibleTo("NoteWidgetTests")] 27 | 28 | // The following GUID is for the ID of the typelib if this project is exposed to COM 29 | [assembly: Guid("01307420-95EF-4ACA-A55A-A49BFACD2EEE")] 30 | 31 | // Version information for an assembly consists of the following four values: 32 | // 33 | // Major Version 34 | // Minor Version 35 | // Build Number 36 | // Revision 37 | // 38 | // You can specify all the values or you can default the Build and Revision Numbers 39 | // by using the '*' as shown below: 40 | // [assembly: AssemblyVersion("1.0.*")] 41 | [assembly: AssemblyVersion("1.0.1.0")] 42 | [assembly: AssemblyFileVersion("1.0.0.0")] 43 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace NoteWidgetAddIn.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.2.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | 26 | [global::System.Configuration.UserScopedSettingAttribute()] 27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 28 | [global::System.Configuration.DefaultSettingValueAttribute("System")] 29 | public string Markdown_ColorScheme { 30 | get { 31 | return ((string)(this["Markdown_ColorScheme"])); 32 | } 33 | set { 34 | this["Markdown_ColorScheme"] = value; 35 | } 36 | } 37 | 38 | [global::System.Configuration.UserScopedSettingAttribute()] 39 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 40 | [global::System.Configuration.DefaultSettingValueAttribute("Default")] 41 | public string Markdown_HighlightTheme { 42 | get { 43 | return ((string)(this["Markdown_HighlightTheme"])); 44 | } 45 | set { 46 | this["Markdown_HighlightTheme"] = value; 47 | } 48 | } 49 | 50 | [global::System.Configuration.UserScopedSettingAttribute()] 51 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 52 | [global::System.Configuration.DefaultSettingValueAttribute("1200")] 53 | public double Markdown_Preview_Width { 54 | get { 55 | return ((double)(this["Markdown_Preview_Width"])); 56 | } 57 | set { 58 | this["Markdown_Preview_Width"] = value; 59 | } 60 | } 61 | 62 | [global::System.Configuration.UserScopedSettingAttribute()] 63 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 64 | [global::System.Configuration.DefaultSettingValueAttribute("1000")] 65 | public double Markdown_Preview_Height { 66 | get { 67 | return ((double)(this["Markdown_Preview_Height"])); 68 | } 69 | set { 70 | this["Markdown_Preview_Height"] = value; 71 | } 72 | } 73 | 74 | [global::System.Configuration.UserScopedSettingAttribute()] 75 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 76 | [global::System.Configuration.DefaultSettingValueAttribute("True")] 77 | public bool Markdown_Preview_Singleton { 78 | get { 79 | return ((bool)(this["Markdown_Preview_Singleton"])); 80 | } 81 | set { 82 | this["Markdown_Preview_Singleton"] = value; 83 | } 84 | } 85 | 86 | [global::System.Configuration.UserScopedSettingAttribute()] 87 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 88 | [global::System.Configuration.DefaultSettingValueAttribute("1500")] 89 | public double Markdown_CheatSheet_Width { 90 | get { 91 | return ((double)(this["Markdown_CheatSheet_Width"])); 92 | } 93 | set { 94 | this["Markdown_CheatSheet_Width"] = value; 95 | } 96 | } 97 | 98 | [global::System.Configuration.UserScopedSettingAttribute()] 99 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 100 | [global::System.Configuration.DefaultSettingValueAttribute("1000")] 101 | public double Markdown_CheatSheet_Height { 102 | get { 103 | return ((double)(this["Markdown_CheatSheet_Height"])); 104 | } 105 | set { 106 | this["Markdown_CheatSheet_Height"] = value; 107 | } 108 | } 109 | 110 | [global::System.Configuration.UserScopedSettingAttribute()] 111 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 112 | [global::System.Configuration.DefaultSettingValueAttribute("0")] 113 | public double Markdown_Preview_Left { 114 | get { 115 | return ((double)(this["Markdown_Preview_Left"])); 116 | } 117 | set { 118 | this["Markdown_Preview_Left"] = value; 119 | } 120 | } 121 | 122 | [global::System.Configuration.UserScopedSettingAttribute()] 123 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 124 | [global::System.Configuration.DefaultSettingValueAttribute("10")] 125 | public double Markdown_Preview_Top { 126 | get { 127 | return ((double)(this["Markdown_Preview_Top"])); 128 | } 129 | set { 130 | this["Markdown_Preview_Top"] = value; 131 | } 132 | } 133 | 134 | [global::System.Configuration.UserScopedSettingAttribute()] 135 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 136 | [global::System.Configuration.DefaultSettingValueAttribute("1")] 137 | public int Markdown_PreviewRefresh_Interval { 138 | get { 139 | return ((int)(this["Markdown_PreviewRefresh_Interval"])); 140 | } 141 | set { 142 | this["Markdown_PreviewRefresh_Interval"] = value; 143 | } 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | System 7 | 8 | 9 | Default 10 | 11 | 12 | 1200 13 | 14 | 15 | 1000 16 | 17 | 18 | True 19 | 20 | 21 | 1500 22 | 23 | 24 | 1000 25 | 26 | 27 | 0 28 | 29 | 30 | 10 31 | 32 | 33 | 1 34 | 35 | 36 | -------------------------------------------------------------------------------- /NoteWidgetAddIn/Properties/documents.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/efreykongcn/NoteWidget/339408ac43f60b6ec29951acc78bea053c0d3734/NoteWidgetAddIn/Properties/documents.ico -------------------------------------------------------------------------------- /NoteWidgetAddIn/Properties/markdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/efreykongcn/NoteWidget/339408ac43f60b6ec29951acc78bea053c0d3734/NoteWidgetAddIn/Properties/markdown.png -------------------------------------------------------------------------------- /NoteWidgetAddIn/Properties/markdown_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/efreykongcn/NoteWidget/339408ac43f60b6ec29951acc78bea053c0d3734/NoteWidgetAddIn/Properties/markdown_icon.ico -------------------------------------------------------------------------------- /NoteWidgetAddIn/Properties/markdownflag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/efreykongcn/NoteWidget/339408ac43f60b6ec29951acc78bea053c0d3734/NoteWidgetAddIn/Properties/markdownflag.png -------------------------------------------------------------------------------- /NoteWidgetAddIn/Properties/openfolder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/efreykongcn/NoteWidget/339408ac43f60b6ec29951acc78bea053c0d3734/NoteWidgetAddIn/Properties/openfolder.png -------------------------------------------------------------------------------- /NoteWidgetAddIn/Properties/ribbon.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 |