I've made a few updates to how my web blog handles user comments:
The gory technical details are in the pull request.
...and I don't mean by writing this post. ;)
I run Kirsle.net on a custom Python CMS I wrote called Rophako and I just added a bunch of improvements to the blog platform in it.
I've been wanting to start working on some larger blog articles, things that could take me a few days to write, and my blog had no support for saving drafts. You had to write and publish your blog posts in one sitting. The only alternative was to make the posts "private," where only the site admin(s) can see them, but that would still cause them to "go live" and be listed along with normal public posts and was a messy workaround.
So now my blogging platform has proper support for saving drafts; they stay invisible (even for admins) on all of the normal blog pages, and can only be seen in bulk on a dedicated "drafts" page. While I was putting all that together, I added similar support for private posts, giving them their own index too where you can see only those posts rather than have to go hunting for them.
For visibility purposes, draft and private posts get little tags next to their author/date lines so an admin can tell at a glance what they're looking at. Normal end users won't see those, though. ;)
I've also finally implemented a feature I wanted to from the beginning: sticky posts. The blog database schema has always had a "sticky" field, but it was always set to false
and the Create/Edit Post page gave no way to change that value. The back-end code did have logic to bucket sticky posts higher on the index list than normal ones, but there was no (easy) way to make a post sticky to begin with.
Sticky posts will also get a little "[Sticky]" tag next to their author/date lines, and those ones can be seen by normal end users.
I also fixed a handful of smaller bugs/problems. I've removed the ability to set a custom date/time when editing a blog post. This caused confusion between your web browser's local time and the time zone of the server. So instead, the server always picks the latest UTC Unix time on new entries. When editing an existing entry, there's a checkbox option to reset the time to latest when saving, if you want to bump an old post to the top.
The most recent feature I added to my website's CMS: multi-file uploads for the photo albums. I've been wanting to get around to this for a while so I can actually upload photo albums in bulk and make better use of that feature on my site. ;)
So I did some research and found some bits of example code here and there, and put together a pure HTML5 multiple-file uploader with progress bar. No Flash, no Java, no Internet Explorer 9 or lower. ;)
A lot of the existing bits of code I found out there weren't quite written in a way that was useful for my purposes. Their code tended to run the upload immediately after getting ahold of the files, i.e. they'd set up an HTML5 drag-and-drop spot and/or a multiple-file <input>
box, and as soon as the user drops their pictures or selects them, the JavaScript would go right to work uploading them one by one to the back-end.
On my CMS I wanted to hold off on the uploading, because there's other form elements to take care of too, i.e. what album to put the pictures into or to apply a caption to them all. So I set up handlers for my file input box and drag-drop site to just put all the File
objects into an array and wait for the submit button to be pushed.
So in my implementation, all the pictures are uploaded at once to the back-end, and there's only one progress bar (for the entire upload). It's possible to have one upload event per individual file, and therefore get progress bars on a file-by-file basis, but this didn't fit into my existing code structure.
Something I think is cool though is, on the back-end I'm using the exact same endpoint to handle uploads using Ajax (for those with JavaScript turned on) and when being POST
ed to directly, i.e. for users with NoScript enabled. In both cases, they hit the /photos/upload
on the server to send the form and images.
When the Ajax is the one doing it, it adds an extra __ajax
form parameter. In this case, the back-end responds with a JSON response telling what the next URL is, and the JavaScript initiates a redirect to that URL. In case the user has JavaScript turned off, and the form POSTs to the back-end directly, the web server sends an HTTP redirect to the next URL.
Anyway, I threw together a quick Python/Flask app to mess with this stuff and figure it all out so I didn't have to worry about trying to wrangle existing code into doing something new. I have it hosted on Github here: https://github.com/kirsle/flask-multi-upload
The real interesting part is in the JavaScript source - only 184 lines of code, including comments and whitespace. Pretty straightforward. The same basic front-end code could be used regardless of the back-end, i.e. it could be uploading to a PHP script or something instead of a Python app. The Python part of the source is pretty short and sweet too.
I've made an update to my Rophako CMS that powers Kirsle.net: it now supports Markdown!
Blog posts can be either written in Markdown, or direct HTML (the old way). In Markdown mode, HTML is currently escaped from the post. I may change this and make it only escape HTML in comments if I find it to be a PITA in the future. ;) Oh, and emoticons still work (they're rendered after Markdown is done).
Markdown works in comments, too, but with some limitations, like I don't allow embedding images. Also, you can write entire pages on your site in Markdown. Just create a page named with a .md
file extension that contains Markdown code and it "just works" (there's a built-in markdown.inc.html
file in the default site that wraps your rendered document in your web design's layout).
Best of all, I'm using a handful of extensions to the Python Markdown module to enable a lot of Github style Markdown features, such as code highlighting. Here's a Python example:
def render_markdown(body, html_escape=True):
"""Render a block of Markdown text.
This will default to escaping literal HTML characters. Set
`html_escape=False` to trust HTML."""
args = dict(
lazy_ol=False, # If a numbered list starts at e.g. 4, show the <ol> there
extensions=[
"fenced_code", # GitHub style code blocks
"tables", # http://michelf.ca/projects/php-markdown/extra/#table
"smart_strong", # Handles double__underscore better.
"codehilite", # Code highlighting with Pygment!
"nl2br", # Line breaks inside a paragraph become <br>
"sane_lists", # Make lists less surprising
],
extension_configs={
"codehilite": {
"linenums": False,
}
}
)
if html_escape:
args["safe_mode"] = "escape"
return markdown.markdown(body, **args)
I'll be revisiting all my old blog posts that have code pasted in them and reformatting them in Markdown for easier maintenance. My old way of pasting code in a blog post was to open the code in vim
, and then run commands like,
:let html_use_css=1
:TOhtml
... which would output an HTML file that syntax highlights the code, and then I'd cut and paste all that junk into my blog. Blech. Markdown will be much cleaner. :D
0.0169s
.