Пример #1
0
 def resources(self):
     for r in super(Thread, self).resources():
         yield r
     for w in self.widgets.itervalues():
         for r in w.resources():
             yield r
     yield ew.JSScript('''
     $(document).ready(function () {
         var thread_tag = $('a.thread_tag');
         var thread_spam = $('a.sidebar_thread_spam');
         var tag_thread_holder = $('#tag_thread_holder');
         var allow_moderate = $('#allow_moderate');
         var mod_thread_link = $('#mod_thread_link');
         var mod_thread_form = $('#mod_thread_form');
         if (mod_thread_link.length) {
             if (mod_thread_form.length) {
                 mod_thread_link.click(function (e) {
                     mod_thread_form.toggle();
                     return false;
                 });
             }
         }
         if (thread_tag.length) {
             if (tag_thread_holder.length) {
                 var submit_button = $('input[type="submit"]', tag_thread_holder);
                 var cancel_button = $('<a href="#" class="btn link">Cancel</a>').click(function(evt){
                     evt.preventDefault();
                     tag_thread_holder.hide();
                     thread_tag.removeClass('active');
                 });
                 submit_button.after(cancel_button);
                 thread_tag.click(function (e) {
                     tag_thread_holder.show();
                     thread_tag.addClass('active');
                     // focus the submit to scroll to the form, then focus the subject for them to start typing
                     submit_button.focus();
                     $('input[type="text"]', tag_thread_holder).focus();
                     return false;
                 });
             }
         }
         if (thread_spam.length) {
             if (allow_moderate.length) {
                 thread_spam[0].style.display='block';
             }
         }
     });
     ''')
     yield ew.JSScript('''
         var global_reactions = %s;
     ''' % utils.get_reactions_json())
     yield ew.JSLink('js/reactions.js')
Пример #2
0
 def resources(self):
     for r in super(TicketForm, self).resources(): yield r
     yield ew.JSScript('''
     $(function(){
         $('#show_attach').click(function(evt) {
             $('#view_attach').show();
             $('#show_attach').hide();
             evt.preventDefault();
         });
         $('form').submit(function() {
             var value = $('div.tagsinput div input').val();
             var exists = $('input.label_edit').tagExist(value);
             var default_value = $('div.tagsinput div input').attr('data-default');
             if ((value !== default_value) && (!exists) && value !== ''){
                 $('input.label_edit').addTag(value);
             }
             $('input[type=submit]', this).attr('disabled', 'disabled');
         });
         $('div.reply.discussion-post a.markdown_preview').click(function(){
             var arrow = $(this).closest('.discussion-post').find('span.arw');
             arrow.hide();
         });
         $('div.reply.discussion-post a.markdown_edit').click(function(){
             var arrow = $(this).closest('.discussion-post').find('span.arw');
             arrow.show();
         });
     });''')
Пример #3
0
 def resources(self):
     for r in super(SubscriptionForm, self).resources():
         yield r
     yield ew.JSScript('''
     $(window).load(function () {
         $('tbody').children(':even').addClass('even');
     });''')
Пример #4
0
    def resources(self):
        yield ew.CSSScript('''.deck li input, .deck li select {
margin: 2px 0 2px 3px;
width: 148px;
}''')
        yield ew.JSScript('''$(function() {
    $('.active-card').each(function() {
        var newitem = $('.new-item', this);
        var adder = $('.adder', this);
        var deleters = $('.deleter', this);
        newitem.remove();
        newitem.removeClass('new-item');
        deleters.click(function(evt) {
            evt.stopPropagation();
            evt.preventDefault();
            var $this = $(this);
            $this.closest('li').remove();
        });
        adder.click(function(evt) {
            evt.stopPropagation();
            evt.preventDefault();
            newitem.clone().insertBefore(adder.closest('li'));
        });
    });
});''')
Пример #5
0
 def resources(self):
     for r in super(NewPostForm, self).resources():
         yield r
     yield ew.JSScript('''
         $(function() {
             $('input[name="title"]').focus();
         });
     ''')
Пример #6
0
 def resources(self):
     for r in super(WikiSubscribeForm, self).resources():
         yield r
     yield ew.JSScript("""
         $('a[href$="#toggle-subscribe"]').click(function() {
             $('#wiki_subscribe_form').submit();
             return false;
         })""")
Пример #7
0
 def resources(self):
     for r in super(CreatePageWidget, self).resources(): yield r
     yield ew.JSScript('''$(function () {
         $('#lightbox_create_wiki_page form').submit(function(){
             location.href = $('#sidebar a.add_wiki_page').attr('href') +
                 encodeURIComponent($('input[name=name]', $(this)).val().replace('/', '-')) + '/edit';
             return false;
         });
     });''');
Пример #8
0
 def resources(self):
     for r in super(ModeratePosts, self).resources():
         yield r
     yield ew.JSScript('''
   (function($){
       var tbl = $('form table');
       var checkboxes = $('input[type=checkbox]', tbl);
       $('a[href=#]', tbl).click(function () {
           checkboxes.each(function () {
               if(this.checked) { this.checked = false; }
               else { this.checked = true; }
           });
           return false;
       });
   }(jQuery));''')
Пример #9
0
    def resources(self):
        for r in super(NeighborhoodOverviewForm, self).resources():
            yield r
        yield ew.CSSLink('css/colorPicker.css')
        yield ew.CSSLink('css/jqfontselector.css')
        yield ew.CSSScript('''
table.table_class, table.input_inner{
  margin: 0;
  padding: 0;
  width: 99%;
}

table.table_class .left{ text-align: left; }
table.table_class .right{ text-align: right; width: 50%;}
table.table_class tbody tr td { border: none; }
table.table_class select.add_opt {width: 5em; margin:0; padding: 0;}
        ''')
        yield ew.JSLink('js/jquery.colorPicker.js')
        yield ew.JSLink('js/jqfontselector.js')
        yield ew.JSScript('''
            $(function(){
              $('.table_class').find('input[type="checkbox"]').each(function(index, element) {
                var cb_name = $(this).attr('name');
                var inp_name = cb_name.substr(0, cb_name.length-4);
                var inp_el = $('div[class="'+inp_name+'-inp"]');

                if ($(this).prop('checked')) {
                  inp_el.hide();
                }

                $(element).click(function(e) {
                  if ($(this).prop('checked')) {
                    inp_el.hide();
                  } else {
                    inp_el.show();
                  }
                });
              });

              $('.table_class').find('input.color').each(function(index, element) {
                $(element).colorPicker();
              });
              $('.table_class').find('input.font').each(function(index, element) {
                $(element).fontSelector();
              });
            });
        ''')
Пример #10
0
 def resources(self):
     for r in ew.TextField(name='subject').resources():
         yield r
     for r in ffw.MarkdownEdit(name='text').resources():
         yield r
     yield ew.JSScript('''$(document).ready(function () {
         $("a.attachment_form_add_button").click(function(evt){
             $(this).hide();
             $(".attachment_form_fields", this.parentNode).show();
             evt.preventDefault();
         });
         $("a.cancel_edit_post").click(function(evt){
             $("textarea", this.parentNode).val($("input.original_value", this.parentNode).val());
             $(".attachment_form_fields input", this.parentNode).val('');
             evt.preventDefault();
         });
      });''')
Пример #11
0
 def resources(self):
     for r in super(TicketForm, self).resources():
         yield r
     yield ew.JSScript('''
     // Sometimes IE11 is not firing jQuery's ready callbacks like
     // "$(function(){...})" or "$(document).ready(function(){...});"
     $(window).load(function(){
         $('form').submit(function() {
             $('input[type=submit]', this).prop('disabled', true);
         });
         $('div.reply.discussion-post a.markdown_preview').click(function(){
             var arrow = $(this).closest('.discussion-post').find('span.arw');
             arrow.hide();
         });
         $('div.reply.discussion-post a.markdown_edit').click(function(){
             var arrow = $(this).closest('.discussion-post').find('span.arw');
             arrow.show();
         });
     });''')
 def resources(self):
     for r in super(TicketForm, self).resources(): yield r
     yield ew.JSScript('''
     $(function(){
         $('#show_attach input').click(function(){
             $('#view_attach').show();
             $('#show_attach').hide();
         });
         $('form').submit(function() {
             $('input[type=submit]', this).attr('disabled', 'disabled');
         });
         $('div.reply.discussion-post a.markdown_preview').click(function(){
             var arrow = $(this).closest('.discussion-post').find('span.arw');
             arrow.hide();
         });
         $('div.reply.discussion-post a.markdown_edit').click(function(){
             var arrow = $(this).closest('.discussion-post').find('span.arw');
             arrow.show();
         });
     });''')
Пример #13
0
 def resources(self):
     yield ew.JSLink('js/jquery.tools.min.js')
     yield ew.JSScript('''
     $(document).ready(function () {
         var badges = $('small.badge');
         var i = badges.length;
         while (i) {
             i--;
             var tipHolder = document.createElement('div');
             tipHolder.id = "tip" + i;
             tipHolder.className = "tip";
             document.body.appendChild(tipHolder);
             $(badges[i]).parent('a[title]').tooltip({
                 tip: '#tip' + i,
                 opacity: '.9',
                 offset: [-10, 0]
             });
         }
     });
     ''')
Пример #14
0
 def resources(self):
     for r in super(ModeratePosts, self).resources():
         yield r
     yield ew.JSScript('''
   (function($){
       var tbl = $('form table');
       var checkboxes = $('input[type=checkbox]', tbl);
       $('a[href=#]', tbl).click(function () {
           checkboxes.each(function () {
               if(this.checked) { this.checked = false; }
               else { this.checked = true; }
           });
           return false;
       });
       $('.col-checkbox').click(function(e){
         if (e.target.tagName === "INPUT") { return; };
         var checkbox = $(this).find('input[type=checkbox]').get(0);
         checkbox.checked = !checkbox.checked;
       });
   }(jQuery));''')
Пример #15
0
    def resources(self):
        def _append(x, y):
            return x + y

        yield ew.JSScript('''
var $allTimezones = $("#tz").clone();
var $t = {};
''' +
                          reduce(_append, [
                              '$t["' + el + '"] = ' + str([name.encode('utf-8')
                                                           for name in country_timezones[el]]) + ";\n"
                              for el in country_timezones]) + '''
function selectTimezone($country){
     if($country == " "){
         $("#tz").replaceWith($allTimezones);
     }
     else{
         $("#tz option:gt(0)").remove();
         $.each($t[$country], function(index, value){
             $("#tz").append($("<option></option>").attr("value", value).text(value))
         })
     }
}''')
Пример #16
0
    def resources(self):
        for r in super(Post, self).resources():
            yield r
        for w in self.widgets.itervalues():
            for r in w.resources():
                yield r
        yield ew.CSSScript('''
        div.moderate {
            color:grey;
        }
        ''')
        yield ew.JSLink('js/jquery.lightbox_me.js')
        yield ew.JSScript('''
        (function () {
            $('div.discussion-post').each(function () {
                var post = this;
                $('.submit', post).button();
                $('.moderate_post', post).click(function(e){
                    e.preventDefault();
                    var mod = $(this).text();

                    if ($(this).hasClass('delete')) mod = 'Delete';
                    else if ($(this).hasClass('approve')) mod = 'Approve';
                    else if ($(this).hasClass('spam')) mod = 'Spam';
                    else if ($(this).hasClass('undo')) mod = 'Undo';


                    if (mod === 'Delete' && !confirm('Really delete this post?')) {
                        return;
                    }
                    $.ajax({
                        type: 'POST',
                        url: this.parentNode.action,
                        data: jQuery(this.parentNode).serialize(),
                        success: function() {
                            if (mod === 'Delete'){
                                $(post).remove();
                            }
                            else if (mod === 'Approve'){
                                $('a.shortlink, form.moderate_spam, form.moderate_approve', post).toggle();
                                $('div.moderate', post).removeClass('moderate');
                            }
                            else if (mod == 'Spam'){
                                spam_block_display($(post), 'show_spam');
                            }
                            else if (mod == 'Undo'){
                                spam_block_display($(post), 'hide_spam');
                            }
                        }
                    });
                });

                function spam_block_display($post, display_type) {
                    var spam_block = $post.find('.info.grid-15.spam-present');
                    var row = $post.find('.row').eq(0);

                    if (display_type == 'show_spam') {
                        spam_block.show();
                        row.hide();
                    } else if (display_type == 'hide_spam') {
                        spam_block.hide();
                        row.show();
                    }
                }

                function get_cm($elem) { return $('.CodeMirror', $elem)[0].CodeMirror; }

                if($('a.edit_post', post)){
                    $('a.edit_post', post).click(function (evt) {
                        evt.preventDefault();
                        $('.display_post', post).hide();

                        // remove the options column, but have to adjust the width of the middle section which is
                        // already hard-coded
                        var $opts = $('.options:first', post);
                        var opts_width = $opts.outerWidth(true);
                        $opts.hide();
                        var $post_middle = $('div.grid-14:first', post);
                        $post_middle.data('original-width', $post_middle.width());
                        $post_middle.width($post_middle.width() + opts_width);

                        var $edit_post_form = $('.edit_post_form', post);
                        var cm = get_cm($edit_post_form);
                        $edit_post_form.show();
                        cm.refresh();
                        cm.focus();
                    });
                    $("a.cancel_edit_post", post).click(function(evt){
                        $('.display_post', post).show();
                        $('.options', post).show();
                        $('.edit_post_form', post).hide();
                        var $post_middle = $('div.grid-14:first', post);
                        $post_middle.width($post_middle.data('original-width'));
                    });
                }
                if($('.reply_post', post)){
                    $('.reply_post', post).click(function (evt) {
                        evt.preventDefault();
                        var $reply_post_form = $('.reply_post_form', post);
                        var cm = get_cm($reply_post_form);
                        $reply_post_form.show();
                        cm.focus();
                    });
                    $('.reply_post', post).button();
                }
                if($('.add_attachment', post)){
                    $('.add_attachment', post).click(function (evt) {
                        evt.preventDefault();
                        $('.add_attachment_form', post).show();
                    });
                }
                if($('.shortlink', post)){
                    var popup = $('.shortlink_popup', post);
                    $('.shortlink', post).click(function(evt){
                        evt.preventDefault();
                        popup.lightbox_me({
                            onLoad: function() {
                                $('input', popup).select();
                            }
                        });
                    });
                    $('.close', popup).bind('click', function() {
                        popup.hide();
                    });
                }
            });

            //lightbox_me script to create lightbox of attached images
            $('.lightbox').click(function(e) {
                var image_source = $(this).data("src");
                var image = $('#lightbox').find('img:first');
                image.attr("src", image_source);

                $('#lightbox').lightbox_me({
                    centered: true
                });

                e.preventDefault();
            });
        }());
        ''')
Пример #17
0
    def resources(self):
        for r in super(Post, self).resources():
            yield r
        for w in self.widgets.itervalues():
            for r in w.resources():
                yield r
        yield ew.JSLink('js/jquery.lightbox_me.js')
        yield ew.JSScript('''
        (function () {
            $('div.discussion-post').each(function () {
                var post = this;
                $('.submit', post).button();
                $('.flag_post', post).click(function (ele) {
                    this.parentNode.submit();
                    return false;
                });
                $('.moderate_post', post).click(function(e){
                    e.preventDefault();
                    var mod = $(this).text();
                    if (mod === 'Delete' && !confirm('Really delete this post?')) {
                        return;
                    }
                    var id_post = $(post).attr('id');
                    $.ajax({
                        type: 'POST',
                        url: this.parentNode.action,
                        data: jQuery(this.parentNode).serialize(),
                        success: function() {
                            if (mod == 'Delete'){
                                $(post).remove();
                            }
                            else if (mod == 'Approve'){
                                $('a.reply_post, a.shortlink, form.moderate_spam, form.moderate_approve', post).toggle();
                                $('div.moderate', post).removeClass('moderate');
                            }
                            else if (mod == 'Spam'){
                                $(post).remove();
                            }
                        }
                    });
                });

                if($('a.edit_post', post)){
                    $('a.edit_post', post).click(function (ele) {
                        $('.display_post', post).hide();
                        $('.edit_post_form', post).show();
                        $('.edit_post_form textarea', post).focus();
                        return false;
                    });
                    $("a.cancel_edit_post", post).click(function(evt){
                        $('.display_post', post).show();
                        $('.edit_post_form', post).hide();
                    });
                }
                if($('.reply_post', post)){
                    $('.reply_post', post).click(function (ele) {
                        $('.reply_post_form', post).show();
                        $('.reply_post_form textarea', post).focus();
                        return false;
                    });
                    $('.reply_post', post).button();
                }
                if($('.add_attachment', post)){
                    $('.add_attachment', post).click(function (ele) {
                        $('.add_attachment_form', post).show();
                        return false;
                    });
                }
                if($('.promote_to_thread', post)){
                    $('.promote_to_thread', post).click(function (ele) {
                        $('.promote_to_thread_form', post).show();
                        return false;
                    });
                }
                if($('.shortlink', post)){
                    var popup = $('.shortlink_popup', post);
                    $('.shortlink', post).click(function(evt){
                        evt.preventDefault();
                        popup.lightbox_me({
                            onLoad: function() {
                                $('input', popup).select();
                            }
                        });
                    });
                    $('.close', popup).bind('click', function() {
                        popup.hide();
                    });
                }
            });
        }());
        ''')
Пример #18
0
 def resources(self):
     for r in super(Post, self).resources():
         yield r
     for w in self.widgets.itervalues():
         for r in w.resources():
             yield r
     yield ew.JSLink('js/jquery.lightbox_me.js')
     yield ew.JSScript('''
     (function () {
         $('div.discussion-post').each(function () {
             var post = this;
             $('.submit', post).button();
             $('.flag_post, .delete_post', post).click(function (ele) {
                 this.parentNode.submit();
                 return false;
             });
             if($('a.edit_post', post)){
                 $('a.edit_post', post).click(function (ele) {
                     $('.display_post', post).hide();
                     $('.edit_post_form', post).show();
                     $('.edit_post_form textarea', post).focus();
                     return false;
                 });
                 $("a.cancel_edit_post", post).click(function(evt){
                     $('.display_post', post).show();
                     $('.edit_post_form', post).hide();
                 });
             }
             if($('.reply_post', post)){
                 $('.reply_post', post).click(function (ele) {
                     $('.reply_post_form', post).show();
                     $('.reply_post_form textarea', post).focus();
                     return false;
                 });
                 $('.reply_post', post).button();
             }
             if($('.add_attachment', post)){
                 $('.add_attachment', post).click(function (ele) {
                     $('.add_attachment_form', post).show();
                     return false;
                 });
             }
             if($('.promote_to_thread', post)){
                 $('.promote_to_thread', post).click(function (ele) {
                     $('.promote_to_thread_form', post).show();
                     return false;
                 });
             }
             if($('.shortlink', post)){
                 var popup = $('.shortlink_popup', post);
                 $('.shortlink', post).click(function(evt){
                     evt.preventDefault();
                     popup.lightbox_me({
                         onLoad: function() {
                             $('input', popup).select();
                         }
                     });
                 });
                 $('.close', popup).bind('click', function() {
                     popup.hide();
                 });
             }
         });
     }());
     ''')
Пример #19
0
 def register_js_snippet(self, text, **kw):
     self.resource_manager.register(ew.JSScript(text, **kw))
Пример #20
0
    def resources(self):
        for r in super(Post, self).resources():
            yield r
        for w in self.widgets.itervalues():
            for r in w.resources():
                yield r
        yield ew.JSLink('js/jquery.lightbox_me.js')
        yield ew.JSScript('''
        (function () {
            $('div.discussion-post').each(function () {
                var post = this;
                $('.submit', post).button();
                $('.flag_post', post).click(function (evt) {
                    evt.preventDefault();
                    this.parentNode.submit();
                });
                $('.moderate_post', post).click(function(e){
                    e.preventDefault();
                    var mod = $(this).text();
                    if (mod === 'Delete' && !confirm('Really delete this post?')) {
                        return;
                    }
                    var id_post = $(post).attr('id');
                    $.ajax({
                        type: 'POST',
                        url: this.parentNode.action,
                        data: jQuery(this.parentNode).serialize(),
                        success: function() {
                            if (mod == 'Delete'){
                                $(post).remove();
                            }
                            else if (mod == 'Approve'){
                                $('a.reply_post, a.shortlink, form.moderate_spam, form.moderate_approve', post).toggle();
                                $('div.moderate', post).removeClass('moderate');
                            }
                            else if (mod == 'Spam'){
                                $(post).remove();
                            }
                        }
                    });
                });

                function get_cm($elem) { return $('.CodeMirror', $elem)[0].CodeMirror; }

                if($('a.edit_post', post)){
                    $('a.edit_post', post).click(function (evt) {
                        evt.preventDefault();
                        $('.display_post', post).hide();

                        // remove the options column, but have to adjust the width of the middle section which is
                        // already hard-coded
                        var $opts = $('.options:first', post);
                        var opts_width = $opts.outerWidth(true);
                        $opts.hide();
                        var $post_middle = $('div.grid-14:first', post);
                        $post_middle.data('original-width', $post_middle.width());
                        $post_middle.width($post_middle.width() + opts_width);

                        var $edit_post_form = $('.edit_post_form', post);
                        var cm = get_cm($edit_post_form);
                        $edit_post_form.show();
                        cm.refresh();
                        cm.focus();
                    });
                    $("a.cancel_edit_post", post).click(function(evt){
                        $('.display_post', post).show();
                        $('.options', post).show();
                        $('.edit_post_form', post).hide();
                        var $post_middle = $('div.grid-14:first', post);
                        $post_middle.width($post_middle.data('original-width'));
                    });
                }
                if($('.reply_post', post)){
                    $('.reply_post', post).click(function (evt) {
                        evt.preventDefault();
                        var $reply_post_form = $('.reply_post_form', post);
                        var cm = get_cm($reply_post_form);
                        $reply_post_form.show();
                        cm.focus();
                    });
                    $('.reply_post', post).button();
                }
                if($('.add_attachment', post)){
                    $('.add_attachment', post).click(function (evt) {
                        evt.preventDefault();
                        $('.add_attachment_form', post).show();
                    });
                }
                if($('.shortlink', post)){
                    var popup = $('.shortlink_popup', post);
                    $('.shortlink', post).click(function(evt){
                        evt.preventDefault();
                        popup.lightbox_me({
                            onLoad: function() {
                                $('input', popup).select();
                            }
                        });
                    });
                    $('.close', popup).bind('click', function() {
                        popup.hide();
                    });
                }
            });
        }());
        ''')
Пример #21
0
def onready(text):
    return ew.JSScript('$(function () {%s});' % text)
Пример #22
0
    def resources(self):
        for r in super(NeighborhoodAddProjectForm, self).resources():
            yield r
        yield ew.CSSLink('css/add_project.css')
        neighborhood = g.antispam.enc('neighborhood')
        project_name = g.antispam.enc('project_name')
        project_unixname = g.antispam.enc('project_unixname')

        yield ew.JSScript('''
            $(function(){
                var $scms = $('input[type=checkbox].scm');
                var $nbhd_input = $('input[name="%(neighborhood)s"]');
                var $name_input = $('input[name="%(project_name)s"]');
                var $unixname_input = $('input[name="%(project_unixname)s"]');
                var $project_url = $('#project_url');
                var $url_fragment = $('#url_fragment');
                var $form = $name_input.closest('form');
                var delay = (function(){
                  var timers = {};
                  return function(callback, ms){
                    clearTimeout (timers[callback]);
                    timers[callback] = setTimeout(callback, ms);
                  };
                })();
                $name_input.focus();
                var update_icon = function($input) {
                    var $success_icon = $input.parent().next().find('.success_icon');
                    var $error_icon = $input.parent().next().find('.error_icon');
                    var is_error = $input.nextAll('.error').is(':visible');
                    $success_icon.toggle(!is_error);
                    $error_icon.toggle(is_error);
                };
                if ($name_input.val() !== '') {
                    update_icon($name_input);
                }
                if ($unixname_input.val() !== '') {
                    update_icon($unixname_input);
                }
                var handle_error = function($input, message) {
                    var $error_field = $input.nextAll('.error');
                    if ($error_field.length === 0) {
                        $error_field = $('<div class="error" style="display: none"></div>').insertAfter($input);
                    }
                    $error_field.text(message).toggle(!!message);
                    $project_url.toggle(!message);
                    update_icon($input);
                };
                $form.submit(function(e) {
                    var has_errors = $name_input.add($unixname_input).nextAll('.error').is(':visible');
                    if (has_errors || $name_input.val() === '' || $unixname_input.val() === '') {
                        e.preventDefault();
                        alert('You must resolve the issues with the project name.');
                        return false;
                    }
                });
                $scms.change(function(){
                    if ( $(this).prop('checked') ) {
                        var on = this;
                        $scms.each(function(){
                            if ( this !== on ) {
                                $(this).prop('checked', false);
                            }
                        });
                    }
                });
                var suggest_name = function(project_name) {
                    return project_name.replace(/[^A-Za-z0-9]+/g, '-').toLowerCase();
                };
                var check_names = function() {
                    var data = {
                        'neighborhood': $nbhd_input.val(),
                        'project_name': $name_input.val(),
                        'project_unixname': $unixname_input.val()
                    };
                    $.getJSON('check_names', data, function(result){
                        handle_error($name_input, result.project_name);
                        handle_error($unixname_input, result.project_unixname);
                    });
                };
                var manual = false;
                $name_input.on('input', function(){
                    if (!manual) {
                        var suggested_name = suggest_name($name_input.val());
                        $unixname_input.val(suggested_name);
                        $url_fragment.text(suggested_name);
                    }
                    delay(check_names, 20);
                });
                $unixname_input.change(function() {
                    manual = true;
                });
                $unixname_input.on('input', function(){
                    $url_fragment.text($unixname_input.val());
                    delay(check_names, 20);
                });
            });
        ''' % dict(neighborhood=neighborhood,
                   project_name=project_name,
                   project_unixname=project_unixname))