src/hdalab/static/hdalab/js/gomina.js
author ymh <ymh.work@gmail.com>
Mon, 27 Apr 2015 17:29:51 +0200
changeset 620 f45d7494332e
parent 601 a671a3d3dbad
child 642 78d5c7f822de
permissions -rw-r--r--
upgrade renkan, correct tagcloud, migrate to lodash

/**
 * @author raph
 */

str_format = function() {
	var s = arguments[0];
	for (var i = 0; i < arguments.length - 1; i++) {
		var reg = new RegExp("\\{" + i + "\\}", "gm");
		s = s.replace(reg, arguments[i + 1]);
	}

	return s;
}

var gomNs = {
    minYear: -5000,
    maxYear: 2010,
    tlPixels: 960,
    tlGamma: 6,
    heatGamma: 2,
    displayedDates: [ -5000, 0, 500, 1000, 1200, 1400, 1600, 1700, 1750, 1800, 1850, 1900, 1950, 2010 ],
    mappingLibrary: 'leaflet',
    gradientStart: [ 212, 237, 250 ],
    gradientEnd: [ 35, 63, 94 ],
    zeroColor: [ 220, 220 ,220 ],
    languageCode: 'fr'
}

function yearToPx(year) {
    return gomNs.tlPixels * Math.pow( ( year - gomNs.minYear ) / ( gomNs.maxYear - gomNs.minYear ), gomNs.tlGamma );
}

function pxToYear(px) {
    return gomNs.minYear + ( gomNs.maxYear - gomNs.minYear ) * Math.pow( px / gomNs.tlPixels, 1 / gomNs.tlGamma );
}

function getGradient(_pos) {
    if (_pos == 0) {
        var _rgb = gomNs.zeroColor;
    } else {
        var _rgb = [],
            _exp = Math.pow(_pos, 1/gomNs.heatGamma);
        for (var i=0; i<3; i++) {
            _rgb.push(Math.floor(_exp*gomNs.gradientEnd[i] + (1-_exp)*gomNs.gradientStart[i]));
        }
    }
    return "rgb(" + _rgb.join(",") + ")";
}

function polygon_to_gmap(polycoords, dbpedia_uri) {
    var _opts =  {
        strokeColor: "#000000",
        strokeWeight: .5,
        fillColor: "rgb(" + gomNs.zeroColor.join(",") + ")",
        fillOpacity: 1
    }
    _opts.paths = polycoords.map(function(path) {
        return path.map(function(coord) {
            return new google.maps.LatLng(coord[1], coord[0]);
        });
    });
    var _polygon = new google.maps.Polygon(_opts);
    _polygon.setMap(gomNs.map);
    google.maps.event.addListener(_polygon, 'click', function(a,b) {
        addFilter('country', dbpedia_uri);
    })
    return _polygon;
}

function showCountriesGmap(geoJson) {
    gomNs.countries = {};
    _.each(geoJson.features, function(feature) {
        var _el = { "properties" : feature.properties };
        if (feature.id == 'ATA') {
            _el.gPolygons = [];
        } else {
            switch(feature.geometry.type) {
                case('Polygon'):
                    _el.gPolygons = [ polygon_to_gmap(feature.geometry.coordinates, feature.properties.dbpedia_uri) ];
                break;
                case('MultiPolygon'):
                    _el.gPolygons = feature.geometry.coordinates.map(function(polygon) {
                        return polygon_to_gmap(polygon, feature.properties.dbpedia_uri);
                    })
                break;
            }
        }
        gomNs.countries[feature.properties.dbpedia_uri] = _el;
    });
}

function showCountriesLeaflet(geoJson) {
    gomNs.countries = {};

    L.geoJson(
        geoJson, {
        onEachFeature : function(_f, layer) {
            var isocode = _f.id;
            layer.setStyle({
                color: "#000000",
                weight: .5,
                fillOpacity: 1,
                fillColor: "rgb(" + gomNs.zeroColor.join(",") + ")"
            });
            layer.on('click', function() {
                addFilter('country', _f.properties.dbpedia_uri);
            });
            gomNs.countries[_f.properties.dbpedia_uri] = {
                "properties" : _f.properties,
                "layer" : layer
            }
        }
    }).addTo(gomNs.map);
}

function addFilter(_type, _label) {
    var _curView = gomNs.sessiondata.views[gomNs.sessiondata.view];
    if (_curView.type == 'filter') {
    	if (_curView[_type].indexOf(_label) < 0) {
        	_curView[_type].push(_label);
    	}
        updateFilters();
    }
}

function removeFilter(_type, _index) {
    var _curView = gomNs.sessiondata.views[gomNs.sessiondata.view];
    if (_curView.type == 'filter') {
        _curView[_type].splice(_index,1);
        updateFilters();
    }
}

function getUpdates() {
    var _params = {},
        _curView = gomNs.sessiondata.views[gomNs.sessiondata.view];
    if (_curView.type == 'filter') {
        if (!(_curView.period[0] == gomNs.minYear && _curView.period[1] == gomNs.maxYear)) {
            _params.period = _curView.period.join(',');
        }
        if (_curView.tag.length) {
            _params.label = _curView.tag.join(',');
        }
        if (_curView.country.length) {
            _params.country = decodeURIComponent(_curView.country.join(','));
        }
        $.getJSON(gomNs.urls['filter'], _params, updateDisplay);
        animLoad();
    }
}

var debouncedGetUpdates = _.debounce(getUpdates, 300);

function updatePeriod(_n, _val) {
    var _curView = gomNs.sessiondata.views[gomNs.sessiondata.view];
    if (_curView.type == 'filter') {
        var _int = parseInt(_val);
        if (_int != NaN) {
            if ((_n == 1 && _val >= _curView.period[0]) || (_n == 0 && _val <= _curView.period[1])) {
                _curView.period[_n] = _int;
            }
            updateFilters();
        }
    }
}

function removePeriod() {
    var _curView = gomNs.sessiondata.views[gomNs.sessiondata.view];
    if (_curView.type == 'filter') {
        _curView.period[0] = gomNs.minYear;
        _curView.period[1] = gomNs.maxYear;
        updateFilters();
    }
}

function changeSpan(_this) {
    var _curView = gomNs.sessiondata.views[gomNs.sessiondata.view];
    if (_curView.type == 'filter') {
        if (!$(_this).children().length) {
            var _el = document.createElement('input'),
                _n = _this.id.split('_')[1];
            _el.value = _curView.period[_n];
            _el.style.width = $(_this).width() + 'px';
            $(_el).focusout(function() {
                updatePeriod(_n, this.value);
            }).keypress(function(e) {
                if (e.keyCode == 13) {
                    updatePeriod(_n, this.value);
                }
            });
            $(_this).html(_el);
            _el.focus();
            _el.select();
        }
    }
}

function updateFilters(initial) {
    if(typeof initial==="undefined"){
        initial = false;
    }
    var _curView = gomNs.sessiondata.views[gomNs.sessiondata.view];
    if (_curView.type != 'filter') {
        return;
    }
    // Prepare renkan link
    var url_renkan = $("#renkan-link").attr("href");
    url_renkan = ((url_renkan.lastIndexOf("?")>=0) ? (url_renkan.substr(0, url_renkan.lastIndexOf("?"))) : url_renkan) + "?";
    // Filter
    var _htmFilters = '',
        _fl = _curView.tag.length,
        _cl = _curView.country.length;
    if (_curView.period[0] == gomNs.minYear && _curView.period[1] == gomNs.maxYear) {
        _htmFilters += '<li class="filperiod">'+gettext("Toutes periodes")+'</li>';
    } else {
        _htmFilters += '<li class="filperiod">'+gettext("Periode&nbsp;:")+' <span class="spyr" id="sp_0" onclick="changeSpan(this);">'
            + _curView.period[0]
            + '</span> ' + gettext('a')+' <span class="spyr" id="sp_1" onclick="changeSpan(this);">'
            + _curView.period[1]
            + '</span><a href="#" class="remfil" onclick="removePeriod(); return false;">[x]</a></li>';
        url_renkan += "period=" + _curView.period[0] + "," + _curView.period[1]
    }
    $("#handle_0").css({
        "left" : yearToPx(_curView.period[0])+"px",
    }).attr("year", _curView.period[0])
    .find(".handleinner")
    .css({
        "margin-left" : "-20px"
    });
    $("#handle_1").css({
        "left" : yearToPx(_curView.period[1])+"px",
    }).attr("year", _curView.period[1])
    .find(".handleinner")
    .css({
        "margin-left" : "0"
    });
    if (_cl) {
        url_renkan += "&country=";
        _htmFilters += _(_curView.country).map(function(_t, _i) {
            // dbpedia uri for renkan url
            url_renkan += "," + ( (typeof gomNs.countries == "object" && typeof gomNs.countries[_t] == "object") ? _t : decodeURIComponent(_t.match('[^/]+$')[0]).replace('_',' '));
            // label for interface
            var country_label = ( (typeof gomNs.countries == "object" && typeof gomNs.countries[_t] == "object") ? gomNs.countries[_t].properties.labels[gomNs.languageCode] : decodeURIComponent(_t.match('[^/]+$')[0]).replace('_',' '));
            return '<li class="filcountry">'+gettext('Pays&nbsp;:')+' '
                + country_label
                + '<a href="#" class="remfil" onclick="removeFilter(\'country\','
                + _i
                + '); return false;">[x]</a></li>';
        }).join("");

    }
    if (_fl) {
        url_renkan += "&label=";
        _htmFilters += _(_curView.tag).map(function(_t, _i) {
            url_renkan += "," + _t;
            return '<li class="filtag">'+gettext('Tag&nbsp;:')+' '
                + '<span class="filtag_label">'+_t+'</span>'
                + '<a href="#" class="remfil" onclick="removeFilter(\'tag\','
                + _i
                + '); return false;">[x]</a></li>';
        }).join("");
    }
    $("#renkan-link").attr("href",url_renkan);
    if(!initial){
        history.replaceState(null, null, url_renkan.substr(url_renkan.lastIndexOf("?")));
    }
    $("#filters").html(_htmFilters).hide();
    debouncedGetUpdates();

}

function displayContents(contentdata) {
    if (contentdata && contentdata.length) {
        var _htmlCl = '<ul id="contentlist">'
            + contentdata.map(function(_d) {
                var _dsurl = gomNs.urls.datasheet.replace(/ID$/,_d.hda_id);
                var _html = '<li class="content-item"><h3>'
                    + ((_d.hda_id)?'<a href="'+_dsurl+ '">':'')
                    + _d.title
                    + ((_d.hda_id)?'</a>&nbsp;<a class="mind-map-icon" href="' + gomNs.urls.renkan + '?notice=' + _d.hda_id + '" target="_blank">placeholder</a>':'')
                    + '</h3>'
                    + ( typeof _d.coords == "object" ?
                        '<div class="maplet"><img src="http://maps.googleapis.com/maps/api/staticmap?center=47,1.5&zoom=4&size=160x160&maptype=roadmap&markers=color:red%7C'
                        + _d.coords.latitude
                        + ','
                        + _d.coords.longitude
                        + '&sensor=false" /><h4>'
                        + gettext('Localisation&nbsp;:')
                        + ' '
                        + _d.coords.city_name
                        + '</h4></div>'
                        : '')
                    + '<h4><a href="'
                    + _d.url
                    + '" target="_blank">'
                    + _d.url.replace(/(^.{40}).+(.{30}$)/m,'$1 &hellip; $2')
                    + '</a></h4><p>'
                    + ((_d.hda_id)?'<a href="'+ _dsurl+ '">':'')
                    + _d.description.replace(/(^.{0,160})([\s]|$)(.*)/,'$1&hellip;')
                    + ((_d.hda_id)?'</a>':'')
                    + '</p><ul class="content-tags">'
                    + _d.tags.map(function(_t) {
                        return '<li class="content-tag-item"><a href="#" onclick="addFilter(\'tag\', this.getAttribute(\'original-label\')); return false;" original-label="'
                            + _t.label
                            + '"'
                            + (_t.match ? ' class="tagmatch"' : '')
                            + '>'
                            + _t.translated_label
                            + '</a>'
                            + '&nbsp;<a class="mind-map-icon-white" href="' + gomNs.urls.renkan + '?label=' + _t.label + '" target="_blank">placeholder</a></h3>'
                            + '</li>';
                    }).join('')
                    + '<div style="clear: both;"></div></ul></div>';
                _html += '</li>';
                return _html;
            }).join('')
            + '</ul>';
        $("#contents").html(_htmlCl).scrollTop(0);

    }
    else {
        $("#contents").html("");
    }
}

function updateMap() {
    if (gomNs.countries && gomNs.filterCountries) {
        var _max = Math.max(1, _(gomNs.filterCountries).max().value());
        _.each(gomNs.countries, function(_country, _k) {
            _k = decodeURIComponent(_k);
            var _val = gomNs.filterCountries[_k] || 0,
                _fill = getGradient(_val/_max);
            switch(gomNs.mappingLibrary) {
                case 'gmaps':
                    _(_country.gPolygons).each(function(_p) {
                        _p.setOptions({
                            "fillColor" : _fill,
                            "fillOpacity" : 1
                        });
                    });
                break;
                case 'leaflet':
                    _country.layer.setStyle({
                        "fillColor" : _fill,
                        "fillOpacity" : 1
                    })
                break;
            }
        });
    }
}


function updateDisplay(data) {
    animStop();

    // translate filters
    $('.filtag_label').each(function(index, elt) {
    	txt = $(this).text();
    	if(txt in data.tagtranslations) {
    		$(this).text(data.tagtranslations[txt]);
    	}
    });
    $("#filters").show();


    if (gomNs.dhmPaper) {
        gomNs.dhmPaper.clear();
    } else {
        gomNs.dhmPaper = new Raphael("dateheat");
    }
    $("#contentcount").html('<b>'+data.count+'</b> ' + ngettext('notice', 'notices', data.count));
    if (!data.sparkline.length || data.sparkline[0].year != gomNs.minYear) {
        data.sparkline.splice(0,0,{"year": gomNs.minYear, "score": 0});
    }
    var _maxheat = _(data.sparkline).max(function(_d) { return parseInt(_d.score); }).value().score;
    _.each(data.sparkline, function(_d, _i) {
        var _nxt = (_i == data.sparkline.length - 1) ? (gomNs.maxYear + 1) : data.sparkline[_i + 1].year,
            _x1 = yearToPx(_d.year),
            _x2 = yearToPx(_nxt),
            _heat = _d.score / _maxheat;
        gomNs.dhmPaper.rect(_x1, 0, _x2 - _x1, 20).attr({
            "fill" : getGradient(_heat),
            "stroke" : "none"
        })
    });
    if (gomNs.sessiondata.view == 0) {
        var _h0 = $("#handle_0").position().left,
            _h1 = $("#handle_1").position().left;
        gomNs.dhmPaper.rect(Math.min(_h0, _h1) - 1, 0, Math.abs(_h0 - _h1) + 2, 20).attr({
            "stroke" : "#cc0066",
            "stroke-width" : "3"
        });
    }
    if (data.tags.length) {
        var _scores = _.map(data.tags, function(_d) { return parseInt(_d.score)}),
            _maxTag = _(_scores).max().value(),
            _minTag = Math.min(_(_scores).min(), _maxTag - 1),
            _scale = 10 / Math.sqrt(_maxTag - _minTag),
            _htmlTc = '<ul id="tclist">'
            + _(data.tags).map(function(_d) {
                return '<li style="font-size:'
                    + parseInt(10 + _scale * Math.sqrt(_d.score - _minTag))
                    + 'px;"><a href="#" onclick="addFilter(\'tag\', this.getAttribute(\'original-label\')); return false;" original-label="'
                    + _d.label
                    +'"'
                    + (_d.match ? ' class="tagmatch"' : '')
                    + '>'
                    + _d.translated_label
                    + '</a></li>';
            }).join('')
            + '</ul>';
        $("#tagcloud").html(_htmlTc);
    }
    else {
        $("#tagcloud").html("<h4>Pas de mots-clés trouvés</h4>");
    }
    displayContents(data.contents);
    if(data.countries) {
        gomNs.filterCountries = data.countries;
        $("#map").trigger('mapUpdate.gomina');
    }
    if (data.disciplines) {
        var _disc = data.disciplines.filter(function(_d) {
                return +_d.score > 0;
            }),
            _max = _disc.reduce(function(_a, _b) {
                return Math.max(_a,_b.score)
            }, 1);
        $("#disciplines").html(
            '<ul class="disc-ul">'
            + _disc.map(function(_d) {
                var _col = getGradient(_d.score / _max);
                return '<li class="disc-li" onclick="addFilter(\'tag\', this.getAttribute(\'original-label\')); return false;" original-label="'
                    + _d.label
                    + '"><div class="disc-label"><a href="#">'
                    + _d.translated_label
                    + '</a></div><div class="disc-bar" style="background:'
                    + _col
                    + '; width:'
                    + Math.floor(120 * (_d.score / _max))
                    + 'px">'
            }).join("")
            + '</ul>'
        )

    }
}


function showView(initial) {
    if(typeof initial==="undefined"){
        initial = false;
    }
    $(".lienvue").removeClass("actif");
    $("#view_" + gomNs.sessiondata.view).addClass("actif");
    var _curView = gomNs.sessiondata.views[gomNs.sessiondata.view];
    $("#titrevue").val(_curView.name);
    $("#bloc_gestvue h2").html(gettext('Gerer la vue')+' "' + _.escape(_curView.name) + '"');
    $("div.bloc").show();
    $("#widgetlist input").prop("checked",true);
    _.each(_curView.hiddenWidgets, function(_w) {
        $("#chbx_" + _w).prop("checked",false);
        $("#" + _w).hide();
    });
    $("#notes").html( _curView.notes
        ? '<ul><li>' + _.escape(_curView.notes).replace(/\n/gm,"</li><li>") + '</li></ul>'
        : ( gomNs.write_allowed ? '<ul><li>'+gettext('Annoter cette vue')+'...</li></ul>' : '' ) );
    switch(_curView.type) {
        case 'list':
            $("#bandefiltre, .handle").hide();
            $.getJSON(gomNs.urls['filter'], {
                contentlist: _curView.list.join(',')
            }, updateDisplay);
            animLoad();
            break;
        case 'filter':
            $("#bandefiltre, .handle").show();
            updateFilters(initial);
            break;
    }
}


function getURLParameter(name) {
    return decodeURI(
        (RegExp(name + '=' + '(.+?)(&|$)').exec(document.location.search)||[,null])[1]
    );
}

function getInitialView() {
    var _urlParam = {
        period: [ gomNs.minYear, gomNs.maxYear ],
        country: [],
        tag: []
    };
    if (document.location.search) {
        var p = decodeURIComponent(getURLParameter("period"));
        if(p!="null"){
            p = p.split(",");
        }
        else{
            p = [ gomNs.minYear, gomNs.maxYear ];
        }
        var c = decodeURIComponent(getURLParameter("country"));
        if(c!="null"){
            c = c.split(",");
            c = c.filter(function(n){ return n!="" });
        }
        else{
            c = [];
        }
        var t = decodeURIComponent(getURLParameter("label"));
        if(t!="null"){
            t = t.split(",");
            t = t.filter(function(n){ return n!="" });
        }
        else{
            t = [];
        }
        _urlParam.period = p;
        _urlParam.country = c;
        _urlParam.tag = t;
    }
    // Not getting session info anymore, build data object
    var data = {
        data: {
            view: 0,
            views: [
                {
                    type: "filter",
                    period: _urlParam.period,
                    country: _urlParam.country,
                    tag: _urlParam.tag
                }
            ]
        }
    };

    gomNs.sessiondata = typeof data.data == "string" ? JSON.parse(data.data) : (typeof data.data == "object" ? data.data : {});

    if (!gomNs.sessiondata.views) {
        gomNs.sessiondata.views = [];
    }
    showView(true);
}


function animLoad() {
    var _d = $("#waiting"),
        _w = _d.width(),
        _h = _d.height(),
        _r = .33*Math.min(_w,_h),
        _count = 24,
        _html = '',
        _f = 2* Math.PI / _count;
    _d.empty().show();
    for (var _i = 0; _i < _count; _i++) {
        var _x = Math.floor(Math.sin(_i * _f)*_r + _w/2),
            _y = Math.floor(-Math.cos(_i * _f)*_r + _h/2),
            _el = document.createElement('div');
        _el.className = 'waittick';
        _d.append(_el);
        $(_el).css({
            "left": _x + "px",
            "top": _y + "px"
        }).delay(200*_i).fadeIn(400).delay(600 + 200* _i).fadeOut();
    }
}

function animStop() {
    $("#waiting").empty().fadeOut();
}
function ellipse(_text, _length) {
    var _rgxp = new RegExp('(^.{0,' + _length + '})([\s]|$)(.*)')
    return _text.replace(/(\n|\r|\r\n)/mg,' ').trim().replace(_rgxp,'$1…')
}

function highlightText(_text, _search) {
    var _rgxp = new RegExp('(' + _search.replace(/(\W)/g, '\\$1') + ')','gi');
    return _text.replace(_rgxp, '<strong>$1</strong>');
}

function wikipediaUrl(_text) {
    return "http://" + gomNs.languageCode + ".wikipedia.org/wiki/" + encodeURI(_text.replace(/ /g,'_'))
}

wpTemplate = _.template(
    '<h4 class="wptitle"><% print(highlightText(item.label, inputvalue)); %></h4><% if (item.thumbnail) { %><img class="wpimg" src="<%-item.thumbnail%>" /><% };'
    + ' if (item.abstract) { %><p class="wpabstract"><% print(ellipse(item.abstract,250))%></p><p class="wpsource"><a href="<% print(wikipediaUrl(item.label)) %>" target="_blank"><% print(gettext("Source&nbsp;: Wikipédia")) %></a></p><% }; %><div class="clear"></div>'
);

acTemplate = _.template(
    '<a><span class="acnb"><%- item.nb %></span><h4 class="actitle"><% print(highlightText(item.label, inputvalue)); %></h4></a>'
);

$(document).ready(function() {
    var showMethod;
    switch(gomNs.mappingLibrary) {
        case 'gmaps':
            gomNs.map = new google.maps.Map(document.getElementById("map"),
                {
                    center: new google.maps.LatLng(30, 0),
                    zoom: 1,
                    mapTypeId: google.maps.MapTypeId.SATELLITE
                });
            showMethod = showCountriesGmap;
            break;
        case 'leaflet':
            gomNs.map = new L.Map('map', {
                center: new L.LatLng(30, 0),
                zoom: 0.80,
                minZoom: 0.80,
                zoomControl: false
            });
            gomNs.map.addControl(new L.Control.ZoomMin())
            //gomNs.map.addLayer(new L.TileLayer("http://s3.amazonaws.com/com.modestmaps.bluemarble/{z}-r{y}-c{x}.jpg", {maxZoom: 9}));
            showMethod = showCountriesLeaflet;
            break;
    }
    $("#map").on('mapUpdate.gomina', updateMap);
    $.getJSON(gomNs.urls['countries'], function(geoJson) {
        showMethod(geoJson);
        $("#map").trigger('mapUpdate.gomina');
    });

    var _html = gomNs.displayedDates.map(function(_v) {
        return '<li style="left: '
            + parseInt(yearToPx(_v))
            + 'px"><div class="datelabel">'
            + _v
            + '</div></li>'
    }).join('');
    $("#dates").html(_html);

    $(".handle").draggable({
        "axis" : "x",
        "containment" : "parent",
        "drag": function() {
            $(this).attr("year",parseInt(pxToYear($(this).position().left)));
            var _curView = gomNs.sessiondata.views[gomNs.sessiondata.view];
            if (_curView.type == 'filter') {
                var _h0 = $("#handle_0"),
                    _h1 = $("#handle_1"),
                    _h0v = parseInt(_h0.attr("year")),
                    _h1v = parseInt(_h1.attr("year"));
                _curView.period = [ Math.min(_h0v, _h1v), Math.max(_h0v, _h1v)];
                _h0.find(".handleinner").css({
                    "margin-left" : (_h0v>_h1v ? "0" : "-20px")
                })
                _h1.find(".handleinner").css({
                    "margin-left" : (_h1v>_h0v ? "0" : "-20px")
                })
                updateFilters();
                //debouncedSaveChanges();
            }
        }
    });

    getInitialView();
    $(".barrebloc").click(function() {
        $(this).next().slideToggle();
    });
    gomNs.widgetList = [];
    var _html = '<ul id="widgetlist">';
    $("div.bloc").each(function() {
       gomNs.widgetList.push(this.id);
       _html += '<li><input type="checkbox" id="chbx_'
        + this.id
        + '" /><label>' + $(this).find("h2").html() + '</label></li>'
    });
    _html + '</ul>';

    $(" #tagform ").submit(function() {
        return false;
    });
    var cache = {}, /*CACHE => http://jqueryui.com/demos/autocomplete/#remote-with-cache */
        lastXhr;
    $( "#tagsearch" ).autocomplete({
        source: function( request, response ) {
            var term = request.term;
            if ( term in cache ) {
                $("#tagsearch").removeClass("waiting");
                response( cache[ term ] );
                return;
            }
            $("#tagsearch").addClass("waiting");
            lastXhr = $.getJSON( gomNs.urls['tag_search'], request, function( data, status, xhr ) {
                cache[ term ] = data;
                if ( xhr === lastXhr ) {
                    response( data );
                    $("#tagsearch").removeClass("waiting");
                }
            });
        },
        minLength: ( gomNs.languageCode == 'ja' ? 1 : 2 ),
        focus: function( event, ui ) {
            $(".wpinfo").html(wpTemplate({
                item: ui.item,
                inputvalue: $("#tagsearch").val()
            }));
        },
        select: function( event, ui ) {
            addFilter('tag', ui.item.original_label);
        }
    })
    .data("ui-autocomplete")._renderItem = function(ul, item) {
        var _contents = acTemplate({
            item: item,
            inputvalue: $("#tagsearch").val()
        });
        return $( "<li>" )
            .data( "item.autocomplete", item )
            .html( _contents )
            .appendTo( ul );
    };
});