a simple accordion menu with jquery Apr
20
1
0

I've seen a lot of bloated scripts trying to attach an accordion effect onto a nested menu that just end up being slow, buggy, complicated, and hard to extend. I think people are over thinking things . If you're using JQuery it's easy enough to write this functionality yourself.

working example

Lets say your HTML looks something like this:

<ul id="accordion">
    <li>
        <h1>First</h1>
        <ul>
            <li><a href="#">section</a></li>
            <li><a href="#">section</a></li>
            <li><a href="#">section</a></li>
        </ul>
    </li>

    <li>
        <h1>Second</h1>
        <ul>
            <li><a href="#">section</a></li>
            <li><a href="#">section</a></li>
            <li><a href="#">section</a></li>
        </ul>
    </li>

    <li>
        <h1>Third</h1>
        <ul>
            <li><a href="#">section</a></li>
            <li><a href="#">section</a></li>
            <li><a href="#">section</a></li>
        </ul>
    </li>
</ul>

You can easily initialise and attach the accordion functions like so:

$(document).ready(function() {
    // initialise
    $('ul#accordion > li > ul').hide();
    $('ul#accordion > li:first-child > ul').show();

    // accordion
    $('ul#accordion > li > h1').click(function() {
        // do nothing if already expanded
        if($(this).next().css('display') == 'none') {
            $('ul#accordion > li > ul').slideUp();
            $(this).next().slideDown();
        }
    });
});

I hope you find this code simple and easy to extend.

comments

integrating recaptcha into a contact form in a django project Apr
15
1
0

I finally had to add a spam blocker on my contact page. Those insidious bots are disturbingly effective at sniffing out forms.

I knew this was going to happen eventually, but I feel captchas are an inconvenience to users so I was trying to delay the inevitable, but it's like attempting to hold back the tide. Only a month after launch I'm receiving over 10 spams a day from my site.

I went with reCAPTCHA. It seemed like it was going to be easy to integrate, it has a Python Plugin, and users are already familiar with how captcha's work. It turns out I was right on all fronts. It's been the right decision.

Here's how I integrated reCAPTCHA into my site. This is also how I wrote my contact application.

First I added two variables to settings.py: RECAPTCHA_PUBLIC_KEY and RECAPTCHA_PRIVATE_KEY and set the values accordingly. Actually, I added these to local_settings.py and imported them into settings.py because I have a policy to never commit passwords and keys into the repository, but you get the idea.

If you want you can write a custom context processor to include these variables in every template, but since I only had one view I needed this for I didn't bother.

I then installed the recapcha-client python library into my virtual environment using pip (you can also use easy_install). Unfortunately I couldn't find any documentation on how to use the recaptcha client, but luckily there's not much to the package and it's easy enough look at the source to figure out what to do.

pip install recaptcha-client

or

easy_install recaptcha-client

Following Seek Nuance's tutorial I then modified my view to import captcha and to check reCAPTCHA before processing the form.

from recaptcha.client import captcha

from django.shortcuts import render_to_response
from django.template import RequestContext
from django.core.mail import send_mail, EmailMessage
from django.http import Http404, HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.contrib.sites.models import Site
from django.conf import settings

from contact.models import Contact
from contact.forms import ContactForm


# Create your views here.
def contact(request):
    template_vars = {
        'section': 'contact',
    }

    template_vars['RECAPTCHA_PUBLIC_KEY'] = settings.RECAPTCHA_PUBLIC_KEY

    if request.POST:
        contact_form = ContactForm(request.POST)
        template_vars['contact_form'] = contact_form

        # Check the form captcha.  If not good, pass the template an error code
        captcha_response = captcha.submit(request.POST.get("recaptcha_challenge_field", None),
                                          request.POST.get("recaptcha_response_field", None),
                                          settings.RECAPTCHA_PRIVATE_KEY,
                                          request.META.get("REMOTE_ADDR", None))

        if not captcha_response.is_valid:
            template_vars['captcha_error'] = "&error=%s" % captcha_response.error_code

        elif contact_form.is_valid():
            send(contact_form)
            return HttpResponseRedirect(reverse('contact_success'))

    else:
        contact_form = ContactForm()
        template_vars['contact_form'] = contact_form

    return render_to_response('contact/contact.html', template_vars, context_instance=RequestContext(request))

Copying straight from the reCAPTCHA client documentation, I then added their Challenge API code into my template. You can put this anywhere in the form you want to apply reCAPTCHA to like so:

<form id="contact-form" action="." method="post" />
<table id="contact">
    {{ contact_form.as_table }}

    <!-- recaptcha -->
    <tr>
        <td></td>
        <td>
          <script type="text/javascript">var RecaptchaOptions = {theme : 'white'};</script>
          <script type="text/javascript" src="http://api.recaptcha.net/challenge?k={{ RECAPTCHA_PUBLIC_KEY }}{{ captcha_error}}">
          </script>

          <noscript>
            <iframe src="http://api.recaptcha.net/noscript?k={{ RECAPTCHA_PUBLIC_KEY }}{{ captcha_error}}"
                    height="300" width="500" frameborder="0"></iframe><br>
            <textarea name="recaptcha_challenge_field" rows="3" cols="40">
            </textarea>
            <input type="hidden" name="recaptcha_response_field" 
                   value="manual_challenge">
          </noscript>
        </td>
    </tr>
    <!-- recaptcha -->

    <tr>
        <td></td>
        <td><input class="button" type="submit" name="submit" value="send"></td>
    </tr>
</table>
</form>

And that was it. It was pretty fast to set up. Now if only I could read that thing, but that's a different problem.

For completeness on how I wrote the contact mail application here's the rest of the views, models, forms, and urls.

# the rest of views.py

def send(contact_form):
    site = Site.objects.get(id=settings.SITE_ID)
    contact = Contact.objects.all()[0]

    # construct email
    from_email = '"%s" <%s>' % (contact_form.cleaned_data['name'], contact_form.cleaned_data['email'])
    send_to = '"%s" <%s>' % (contact.user.first_name + ' ' + contact.user.last_name, contact.user.email)
    subject = '[' + site.name + ' contact] ' + contact_form.cleaned_data['subject']

    if contact_form.cleaned_data['website']:
        message = 'website: %s\n\n' % (contact_form.cleaned_data['website'])
    else:
        message = ''

    message += contact_form.cleaned_data['message']

    #send email
    email = EmailMessage(subject, message, from_email, (send_to,), headers = {'Reply-To': from_email})
    email.send(fail_silently=False)


def success(request):
    template_vars = {
        'section': 'contact',
    }

    return render_to_response('contact/success.html', template_vars, context_instance=RequestContext(request))

models.py

from django.db import models
from django.contrib.auth.models import User


# Create your models here.
class Contact(models.Model):
    user = models.ForeignKey(User, help_text='This is the person who will be receiving emails from the website contact.')

    def __unicode__(self):
        return self.user.username

    # for now set up as a singleton
    def save(self):
        self.id = 1
        super(Contact, self).save()

    def delete(self):
        pass

forms.py

from django import forms
from django.contrib.auth.models import User


class ContactForm(forms.Form):
    name = forms.CharField(max_length=100)
    email = forms.EmailField()
    website = forms.URLField(required=False)
    subject = forms.CharField(max_length=100)
    message = forms.CharField(widget=forms.Textarea)

urls.py

from django.conf.urls.defaults import *

urlpatterns = patterns('digitaldreamer.contact.views',
    url(r'^success/, 'success', name='contact_success'),
    url(r'^, 'contact', name='contact'),
)

comments

clearing the cache in google chrome and firefox Apr
13
1
0

It's not inherently obvious where to clear the cache and browsing history in Google Chrome. In Firefox you can go to it directly by selecting: Tools -> Clear Recent History...

It's a little less direct in Chrome. Click on the wrench on the top right of the browser -> Options -> Under the Hood (tab) -> Privacy (heading) -> Clear browsing data... (button).

Alternatively you can bring up the [Clear browsing data] option window by typing:

Ctrl + Shift + Del

This shortcut works in both Chrome and Firefox.

comments

setting the default editor for git commit messages Apr
07
1
0

Here's how you can set the default editor when commenting on git commits.

From man git-commit:

Environment And Configuration Variables

The editor used to edit the commit log message will be chosen from the GIT_EDITOR environment variable,
the core.editor configuration variable,
the VISUAL environment variable,
or the EDITOR environment variable (in that order).

examples:

git config --global core.editor "vim"
export VISUAL=vim
export EDITOR=vim

The EDITOR has the advantage that a number of other programs use this setting.

comments

.emacs function to split windows Apr
05
1
0

I personally like to split my emacs into three windows. I have a certain setup that I like, and I wrote a function to quickly execute the command sequence C-x 3, C-x o, C-x 2. This way I can quickly switch back and forth from a one to three window setup by typing: M-x split-windows.

I'm quite terrible with Lisp, so I'm posting here so I can remember what I did. I'd like to someday make improvements so that it remembers which buffer was open in each window, but this will do for now.

;; split windows
(defun split-windows ()
  (interactive)
  (split-window-horizontally)
  (other-window 1)
  (split-window-vertically))

comments

append a file and exporting the path variable in .bashrc file Apr
05
1
0

If you need to include a file in your PATH, you can append it to the existing variable in your .bashrc script file.

export PATH=$PATH:.:~/bin

comments

create an alias in .bashrc file for the bash shell Apr
05
1
0

Sometimes it's helpful to create an alias for common commands. You can insert them into your .bashrc file.

 alias source_project='source ~/envs/project/bin/activate'

comments

reload a file in emacs Apr
05
1
0

You can reload a file in emacs. I typically will come across this situation after I've done a pull.

M-x revert-buffer

comments

how to reload the .emacs file without restarting emacs Apr
05
1
0

If you've made edits to your .emacs file you can reload it without having to restart your emacs.

M-x load-file
~/.emacs

Alternatively you can highlight a region and execute the expression.

c-x c-e

comments

anchoring a footer to the bottom of the html page using css Apr
03
1
0

It's a common need to anchor a footer to the bottom of your web page. It's a tricky problem because you need to account for both large and small content. I've seen people suggest ass-backward ways of doing this with JavaScript. You can achieve this strictly with HTML and CSS with minimal bloat to your markup. All you need is a container div.

Set the height of html and body to 100%, insert a container div with min-height 100% and relative position, and nest the footer with position: absolute, bottom: 0;

/* css */
html, body {
    height: 100%;
}

#container {
    position: relative;
    min-height: 100%;
}

#footer {
    position: absolute;
    bottom: 0;
}


<!-- html -->
<html>
<head></head>

<body>
  <div id="container">
    <div id="footer"></div>
  </div>
</body>
</html>

You might want to add some padding to the bottom of the container so that your content won't run under the footer.

comments