Net-ng/kansha

View on GitHub
kansha/toolbox/autocomplete.py

Summary

Maintainability
A
35 mins
Test Coverage
# -*- coding:utf-8 -*-
#--
# Copyright (c) 2012-2014 Net-ng.
# All rights reserved.
#
# This software is licensed under the BSD License, as described in
# the file LICENSE.txt, which you should have received as part of
# this distribution.
#--

import random

import webob.exc

from nagare import ajax
from nagare import presentation
from nagare.ajax import YUI_PREFIX


class Autocomplete(object):

    """
    Enhance an existing field by providing an auto-completion feature.

    Parameters:
      - ``field_id``: the field (input or textarea) that should be enhanced
      - ``completion_func``: a function that returns the completion suggestions
        for a given query: it could be a collection of name strings or a
        collection of (name, markup) pairs; the markup is shown in the
        drop-down list (or the name when markup is not available) and the name
        is inserted in the field when the item is selected
      - ``delimiter``: specify the delimiter used if the field is multi-valued
    """

    def __init__(self, field_id, completion_func, delimiter=None,
                 min_query_length=3, max_results_displayed=20):
        self.field_id = field_id
        self.completion_func = completion_func
        self.delimiter = delimiter
        self.min_query_length = int(min_query_length)
        self.max_results_displayed = int(max_results_displayed)
        self.var = 'autocomplete' + str(random.randint(10000000, 99999999))

    def _completion_results(self, query, static_url):
        def make_pair(item):
            if hasattr(item, '__iter__'):
                return item
            else:
                return item, item

        results = self.completion_func(query, static_url)
        return [make_pair(item) for item in results]


def json_response(data):
    """Create a JSON response from the data"""
    return webob.exc.HTTPOk(json_body=data)


@presentation.render_for(Autocomplete, model='static_dependencies')
def render_static_dependencies(self, h, comp, *args):
    # Unused for now...
    for mod in ('autocomplete',):
        h.head.css_url(YUI_PREFIX +
                       '/%(mod)s/assets/skins/sam/%(mod)s.css' % dict(mod=mod))

    h.head.javascript_url(YUI_PREFIX + '/yahoo-dom-event/yahoo-dom-event.js')
    for mod in ('connection', 'animation', 'json',
                'datasource', 'autocomplete'):
        h.head.javascript_url(
            YUI_PREFIX + '/%(mod)s/%(mod)s-min.js' % dict(mod=mod))
    h.head.javascript_url('js/autocomplete.js')
    return h.root


@presentation.render_for(Autocomplete)
def render_autocomplete(self, h, comp, *args):

    static_url = h.head.static_url

    def get_results(query):
        raise json_response(self._completion_results(query, static_url))

    h << h.script(
        'var %(var)s = YAHOO.kansha.autocomplete.init(%(field_id)s,'
        ' %(completion_url)s, %(delimiter)s, %(min_query_length)s, '
        '%(max_results_displayed)s)' %
        {
            'var': self.var,
            'field_id': ajax.py2js(self.field_id),
            'completion_url': ajax.py2js(
                h.add_sessionid_in_url(
                    params=(
                        '_a',
                        '%s=' % h.register_callback(1, get_results, False)
                    )
                )
            ),
            'delimiter': ajax.py2js(self.delimiter),
            'min_query_length': self.min_query_length,
            'max_results_displayed': self.max_results_displayed,
        }
    )

    return h.root