-
Adding a simple WYSIWYM Markdown editor to your models
March 9, 2009 at 10:01:54 CETI'm a Markdown fan. Period. Since I first discovered it some years ago, I've been using it for storing all my "output-to-HTML" texts.
Blango, the blog engine I wrote for this site, uses Markdown for post contents. As I've said, I really like Markdown, but typing (and sometimes escaping) all those *[]() gets boring from time to time. I've been looking for something like a WYSIWYG editor for some time, but none of the available choices seemed good enough for me. However, I recently stumbled upon WMD.
So, what's WMD and why should I care?
In the author's own words:
So WMD is something new: a Wysiwym Markdown editor.
Wysiwym stands for What You See Is What You Mean. WMD produces clean semantic HTML, leaving presentation details like fonts and colors up to style sheets. But you're not left in the dark about cosmetics; as you type, WMD's live preview shows you exactly what your text will look like after the current styles have been applied.
Markdown is a simple markup language that's as easy to read and write as plain-text email. WMD uses Markdown as an input format, converting it into HTML behind the scenes. You can also mix raw HTML with Markdown, so the full expressiveness of HTML is always there if you need it.
Plus, WMD is comprised of Javascript and image files, doesn't need server support, doesn't depend on any Javascript Framework and it's just a small rectangle over the textarea. Id est, it doesn't get in my way.
Downloading the required files
WMD was a hosted service until recently and is currently provided as a set of Javascript obfuscated files. The author is working on a new release, but this is all we got for now. Anyway, good enough.
You can get the last version (1.0.1 as the time of this writing) from project's downloads page. Just open the zipfile and copy the wmd directory to your MEDIA_ROOT.
If you're storing your posts as Markdown and doing the conversion to HTML (as you should be doing), you need to take one extra step. Open wmd/wmd.js and change line 4 to read:
Attacklab.wmd_defaults={version:1,output:"Markdown",lineLength:40,delayLoad:false};
WMD will preprocess the Markdown and send HTML to the server otherwise.
Adding WMD support to your models
By default, WMD will attach an editor to every textarea. So, all we need to do is tell the admin interface to include wmd/wmd.js when adding or editing our models. This can be done by using the inner class Media in your ModelAdmin subclass. For example:
class EntryAdmin(admin.ModelAdmin): class Media: js = ( 'js/wmd/wmd.js', )
And you're ready to go. Now your models will have a small rectangle featuring the WMD over every textarea.
-
Leaving byNotes
Feb. 15, 2009 at 23:18:54 CETWell, let me start by explaining all those mails about byNotes I haven't answered in the last few months. Around mid November I got contacted by the recruiting staff of a social network. At that time, I was still working in the project for my degree (computer science students in Spain are required to write a project for the university in order to get the degree) and I wanted to concentrate on it, but I decided to just take the interviews just in case. They finally told me they wanted me to join them and we agreed to continue the negotiations once I had finished my project.
Fast forward to January, my project is done and christmas holidays are gone, time to reestablish negotiations. Salary is good, schedule is very good (telecommuting 99% of the time) but there's something bad: I must leave byNotes, since management considers it's competing with them.
It wasn't an easy decision, but it was the best option. byNotes has been very fun, but also such a time drain to me, and I haven't got any single eurocent from it. Plus, I'm a coder, not a designer nor a business guy, and I don't have too much money to spend on it. So I really don't think I could make it profitable.
As of today, I've been already working for my new employer for some weeks. My name still figures as the domain holder for bynotes.com and in some about pages, but that should change soon. I'm sure the new maintainers will do a good job at keeping the project alive.
And now comes the interesting part for you, developers. What happens with my free software projects? Well, I'm keeping all of them, but I won't be able to spend some much time working on them. Since I won't be owning byNotes anymore, I'm moving them to GitHub and using LightHouse for ticket tracking. The following is the list of projects I'll be moving to GitHub in the next few days:
Django projects
- Blango
- wapi
- django-bundles
- django-geonames
- django-geocoding
- django-storage
- django-mediafiles
- django-oauthsp
Python projects
- ffmpeg bindings
Cocoa projects
- My fork of OAuthConsumer (fixing some bugs, implementing some goodies)
- BNMaps (map framework)
-
URLsafe base64 encoding/decoding in two lines
Aug. 28, 2008 at 02:42:51 CESTSimon has recently featured this snippet which shrinks a SHA1 hash from 40 to 27 characters using base65 encoding. I've been using another approach for some time and, modestly, I think mine is better, so let me tell you how I do it before you start using the suboptimal approach.
Python does it for us
First, the base64 module already provides a pair of functions, aptly named urlsafe_b64encode and urlsafe_b64decode, which do quasi-safe url encoding using base64. For example:
>>> base64.urlsafe_b64encode(sha1('foobar').digest()) 'iEPX-SQWIR3p67lj_0zigSWTKHg='
The problem here is the equal sign, since we can't put it safely in a URL. However, since we are using this to store a hash and we're going to generate the hash again when we verify the data, we can encode the hash again instead of decoding the base64-encoded string, which lets us safely remove the equal sign. Furthermore, we are also using 27 characters, the same as the other more complex implementation.
Can we decode it? Sure!
Sometimes, you'll want to decode the base64 encoded data. However, once we remove the equal sign, we can't no longer pass the base64 encoded string to urlsafe_b64decode:
>>> base64.urlsafe_b64decode('iEPX-SQWIR3p67lj_0zigSWTKHg') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python2.5/base64.py", line 112, in urlsafe_b64decode return b64decode(s, '-_') File "/usr/lib/python2.5/base64.py", line 76, in b64decode raise TypeError(msg) TypeError: Incorrect padding
Let's examine how base64 works. The input string is processed in 3-byte blocks which are split into 6-bits pieces. Hence, we have 2^6 == 64 possible values per piece which translates to a single character into our base64 alphabet. So, every three byte block is translated to a 4 characters string. When the last block has less than three bytes, it's padded with zeros and one equal sign is added for every padding byte. This leads us to the conclusion that base64 encoded strings always have a length divisible by four. Let's take advantage of this:
>>> s = 'iEPX-SQWIR3p67lj_0zigSWTKHg' >>> base64.urlsafe_b64decode(s + '=' * (4 - len(s) % 4)) '\x88C\xd7\xf9$\x16!\x1d\xe9\xeb\xb9c\xffL\xe2\x81%\x93(x'
So now we have our original string back.
Putting it all together
from base64 import urlsafe_b64encode, urlsafe_b64decode def uri_b64encode(s): return urlsafe_b64encode(s).strip('=') def uri_b64decode(s): return urlsafe_b64decode(s + '=' * (4 - len(s) % 4))