Noah W.'s blog is full of technological exploration, findings, programming, and the life of a young developer.
I know it's been a bit quiet here the last few weeks and I've been quite busy working on a few updates to Furthermark and to my website. In the meantime, I've introduced a new dark mode theme to Noah W.org. It works by toggling between two CSS themes and determining which one to use by storing a cookie.
Access the new feature by toggling modes by clicking (or tapping) on the sun or moon icon in the top-right of the page.
Note: The cookie stored is only used to identify the theme and not used to track you at all. I'm not smart enough to try to track someone anyway.
Published: 12/15/2018 7:42 PM
Article by: Noah Wood
In a recent blog post on my website redesign, I remarked that I had been using Markdown to write my blog posts. I have come to quite like Markdown as a format to use to write sine it keeps my hands on the keyboard and enables an easy way to format my posts without the need to use a full-featured work processing application.
I have been using MarkdownPad as my markdown editor as it appeared to be the only good editor available on Windows (side note: why is it that all of the interesting markdown development is happening on macOS?). The problem with MarkdownPad is that it hasn't been updated in some time (it seems new development has stopped) and on Windows 10 it requires some very specific developer library to be installed in order to get the live preview functionality to work. I haven't seen any good UWP markdown editors in the Windows Store, so I thought: why don't I make one myself?
Enter Furthermark. I created Furthermark as a simple UWP markdown editor that uses some of my favorite features of MarkdownPad. Namely:
I think I came pretty close. There's still a long road ahead, but I think I have a pretty good version 1.0.
UWP is an interesting platform to develop for; the sandboxing and the built-in controls don't have the flexibility that Win32 or traditional .NET development allow for. As an application that will only target desktop platforms, Furthermark had to sacrifice some "traditional" application paradigms in order to get the results I wanted.
The biggest example is the resize slider for the preview window. Most windows control libraries (WinForms, WPF, MFC) have a control for a resize panel or a slider. UWP does not. I could (and would like to in a future version) implement my own control that behaves similarly to a resize panel, but it would take a lot of extra effort. So for now, I implemented a slider control to change the size. Not ideal, but it works.
The other example is the status bar. I wanted a status bar to show
These are things that a lot of people expect from a text editor. Common editors from Notepad to Microsoft Word have some variation of these features. Should be pretty easy, right? As it turns out the status bar became the hardest part to implement. Getting the bar with no content was easy. Furthermark uses a single frame with a UWP Grid control, so my "status bar" is just the last row in my grid. Done.
The hard part were the items inside the status bar. In my first out of (hopefully) many posts, I want to outline how I got the status bar working the way I wanted it to. I plan to opensource Furthermark once I get it working the way I want and clean up some of the code.
Also, I want to warn you all, I wanted to brush up on some of my modern .NET Syntax, and I was lacking in the VB.NET arena, so as a challenge to myself, I wrote Furthermark in VB.NET. If you don't like it, you certainly don't have to keep reading.
This was probably one of the easier ones. I made a read-only property for wordcount that I raise a property changed notification for when the text changes. This property calls a RegEx match to split out on certain types of whitespace. It's fast and fairly accurate.
Public ReadOnly Property WordCount As String Get Dim EditorString As String, Count As Integer = 0 Editor.Document.GetText(Windows.UI.Text.TextGetOptions.None, EditorString) If Not String.IsNullOrWhiteSpace(EditorString) Then Dim col As MatchCollection = Regex.Matches(EditorString, "[\S]+") Count = col.Count End If Return Count.ToString("N0") End Get End Property
These two were the easiest. The RichEditBox control I'm using for the editor has methods to get the line count (and strings have a length property). All I do is set a private
Integer variable to the line count and length and have read-only public properties to call
ToString("N0") on these in order to give myself the comma separator for when we go over one thousand lines or characters.
When you save the document or copy the HTML of the Markdown, you get a notification that fades in and out temporarily from the status bar. I have a method to raise a notification:
Private Async Sub ShowStatusNotification(ByVal Text As String) StatusText = Text RaisePropertyChanged(NameOf(StatusText)) RaiseStatusText.Begin() Await Task.Delay(4000) ExitStatusText.Begin() End Sub
I have a storyboard in the XAML to fade in and out over a duration of 1000ms (one second). This method sets the status text, brings in the text, waits for 4000ms (four seconds) and then fades it back out.
<StackPanel.Resources> <Storyboard x:Name="RaiseStatusText"> <FadeInThemeAnimation TargetName="StatusTextTextBlock" Duration="1000"/> </Storyboard> <Storyboard x:Name="ExitStatusText"> <FadeOutThemeAnimation TargetName="StatusTextTextBlock" Duration="1000"/> </Storyboard> </StackPanel.Resources>
This one wasn't a complete necessary, but I really wanted to have this implemented. The most simple text editor on Windows (Notepad) has this feature (event if it wasn't as simple as it seemed) and I wanted it too. My problem was overthinking the math behind trying to figure this out, and the inconsistent nature of pulling the text from the RichEditBox. The most important thing I learned was getting the text and replacing the line endings to use
Lf rather than the Windows default of
The next step was splitting the text and getting the cursor position to determine where in the line the cursor was.
Dim Col As Integer, LastNewLine As Integer, Text As String ThisEditor.Document.GetText(TextGetOptions.UseLf, Text) Col = ThisEditor.Document.Selection.EndPosition While Col > Text.Length And Col > 0 Col -= 1 End While Text = Text.Substring(0, Col) LastNewLine = Text.LastIndexOf(vbLf) Me.Col = Col - LastNewLine RaisePropertyChanged(NameOf(Col)) _Line = Text.Count(Function(a) a = CChar(vbLf)) + 1 RaisePropertyChanged(NameOf(Line))
What I do here is:
This is the one item I actually really didn't want to have, but unfortunaly the RichEditBox control supports using the Insert key to change the text typing mode from insert to overwrite, and I wanted a way to show the user how the editor was going to behave. This wasn't super hard to implement in the end. It turns out the RichEditBox control will show what the type mode is as a enumeration flag when looking at the Document's
Options property. So I have an event handler on the
PreviewKeyDown event of the edit box (regular
KeyDown doesn't register the "Insert" key) to set a private variable.
_IsOverwrite = Not ThisTextBox.Document.Selection.Options.HasFlag(SelectionOptions.Overtype) RaisePropertyChanged(NameOf(InsOvr))
Then a read-only string property will get the text result of the status.
Public ReadOnly Property InsOvr As String Get Dim Result As String = "INS" If _IsOverwrite Then Result = "OVR" End If Return Result End Get End Property
Like I mentioned above, I'd like to make the application opensource at some point, but I'm not quite ready for the world to see my mess of code. I will also post an update once the application is available on the Windows store, it's currently going through the certification process. I will post updates here on my blog as well as on the official website Furthermark.com.
Published: 7/9/2018 9:04 PM
Article by: Noah Wood
On March 23rd, I was finally able to update my website with a new version I had been working on. My previous website was old, and written in ASP.NET 3 Web forms using VB.NET (as an aside, I have no problem with VB.NET, it compiles to the same bytecode as C#, sometimes I actually like the syntax too). Yuck. When I first began the previous implementation of the site, I had only just started learning .NET and the only other backend web technology I knew was PHP at the time. A lot has changed since then and it was time for a more modern look.
My goals with the new design were to:
I'd like to dig into each of these goals in a bit more detail and explain my thought process behind them.
The Design I had was showing its age. I wanted something simple, modern, and I wanted it to use a dark green color. I had always liked the design of (the now defunct site) Newsvine. So I found a color scheme that used dark green for the header and a light grey for the background. The header is simple, with the links following as buttons and as a "hamburger" menu for the mobile version.
When Microsoft announced .NET Core, I was excited. I had become pretty familiar with .NET/C#/VB.NET over the years and was happy to hear there was a version that was both cross-platform and even faster than the .NET Framework implementation. I chose to use .NET Core (in C# this time, so calm down) and implement a hybrid approach and use both MVC where it makes sense and Razor pages for everything else. Essentially the MVC approach was used for the blog and the admin console and pages for everything else. Starting with an empty project makes this pretty trivial to implement.
I use Markdown to write my blog posts. I wanted my blog engine to store the markdown post in the database and pull it, and convert it into HTML on-the-fly. Using Markdig made this easy. A simple (razor) call to the library worked.
That was it. Problem solved.
There is an admin section. It's not complete yet, but it's there. There is currently no way to register (aside from manually inserting into the database) to be a User, but the login works well. I'm using salted Blowfish encryption. Much like Markdig made markdown easy, BCrypt.NET-Core makes it easy to implement this encryption. Using a combination of:
I think I have a solid implementation of a secured area of my site. The built-in methods for authentication in .NET Core make using cookies to control authorization quite easy.
Going forward, as I finish up the final pieces of the backend site, I'd like to open source some of my code. Look forward to part two of this post in the near future!
Published: 3/31/2018 12:08 PM
Article by: Noah Wood