Commit c44a94e8 authored by Shashi Gowda's avatar Shashi Gowda

Port autocomplete from tagInput to jQuery UI, send Last-Modified header and look for it in JS.

parent e5495e7d
......@@ -34,6 +34,8 @@ if (!defined('STATUSNET')) {
class PeopletagautocompleteAction extends Action
{
var $user;
var $tags;
var $last_mod;
/**
* Check pre-requisites and instantiate attributes
......@@ -66,13 +68,47 @@ class PeopletagautocompleteAction extends Action
return false;
}
$profile = $this->user->getProfile();
$tags = $profile->getOwnedTags(common_current_user());
$this->tags = array();
while ($tags->fetch()) {
if (empty($this->last_mod)) {
$this->last_mod = $tags->modified;
}
$arr = array();
$arr['tag'] = $tags->tag;
$arr['mode'] = $tags->private ? 'private' : 'public';
// $arr['url'] = $tags->homeUrl();
$arr['freq'] = $tags->taggedCount();
$this->tags[] = $arr;
}
$tags->free();
return true;
}
/**
* Last modified time
*
* Helps in browser-caching
*
* @return String time
*/
function lastModified()
{
return strtotime($this->last_mod);
}
/**
* Handle request
*
* Does the subscription and returns results.
* Print the JSON autocomplete data
*
* @param Array $args unused.
*
......@@ -81,24 +117,11 @@ class PeopletagautocompleteAction extends Action
function handle($args)
{
$profile = $this->user->getProfile();
$tags = $profile->getOwnedTags(common_current_user());
$tags_array = array();
while ($tags->fetch()) {
$arr = array();
$arr['tag'] = $tags->tag;
$arr['mode'] = $tags->private ? 'private' : 'public';
// $arr['url'] = $tags->homeUrl();
$arr['freq'] = $tags->taggedCount();
$tags_array[] = $arr;
//common_log(LOG_DEBUG, 'Autocomplete data: ' . json_encode($this->tags));
if ($this->tags) {
print(json_encode($this->tags));
exit(0);
}
$tags->free();
//common_log(LOG_DEBUG, 'Autocomplete data: ' . json_encode($tags_array));
print(json_encode($tags_array));
exit(0);
return false;
}
}
This diff is collapsed.
/**
* jQuery.timers - Timer abstractions for jQuery
* Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com)
* Licensed under the WTFPL (http://sam.zoy.org/wtfpl/).
* Date: 2009/10/16
*
* @author Blair Mitchelmore
* @version 1.2
*
**/
jQuery.fn.extend({
everyTime: function(interval, label, fn, times) {
return this.each(function() {
jQuery.timer.add(this, interval, label, fn, times);
});
},
oneTime: function(interval, label, fn) {
return this.each(function() {
jQuery.timer.add(this, interval, label, fn, 1);
});
},
stopTime: function(label, fn) {
return this.each(function() {
jQuery.timer.remove(this, label, fn);
});
}
});
jQuery.extend({
timer: {
global: [],
guid: 1,
dataKey: "jQuery.timer",
regex: /^([0-9]+(?:\.[0-9]*)?)\s*(.*s)?$/,
powers: {
// Yeah this is major overkill...
'ms': 1,
'cs': 10,
'ds': 100,
's': 1000,
'das': 10000,
'hs': 100000,
'ks': 1000000
},
timeParse: function(value) {
if (value == undefined || value == null)
return null;
var result = this.regex.exec(jQuery.trim(value.toString()));
if (result[2]) {
var num = parseFloat(result[1]);
var mult = this.powers[result[2]] || 1;
return num * mult;
} else {
return value;
}
},
add: function(element, interval, label, fn, times) {
var counter = 0;
if (jQuery.isFunction(label)) {
if (!times)
times = fn;
fn = label;
label = interval;
}
interval = jQuery.timer.timeParse(interval);
if (typeof interval != 'number' || isNaN(interval) || interval < 0)
return;
if (typeof times != 'number' || isNaN(times) || times < 0)
times = 0;
times = times || 0;
var timers = jQuery.data(element, this.dataKey) || jQuery.data(element, this.dataKey, {});
if (!timers[label])
timers[label] = {};
fn.timerID = fn.timerID || this.guid++;
var handler = function() {
if ((++counter > times && times !== 0) || fn.call(element, counter) === false)
jQuery.timer.remove(element, label, fn);
};
handler.timerID = fn.timerID;
if (!timers[label][fn.timerID])
timers[label][fn.timerID] = window.setInterval(handler,interval);
this.global.push( element );
},
remove: function(element, label, fn) {
var timers = jQuery.data(element, this.dataKey), ret;
if ( timers ) {
if (!label) {
for ( label in timers )
this.remove(element, label, fn);
} else if ( timers[label] ) {
if ( fn ) {
if ( fn.timerID ) {
window.clearInterval(timers[label][fn.timerID]);
delete timers[label][fn.timerID];
}
} else {
for ( var fn in timers[label] ) {
window.clearInterval(timers[label][fn]);
delete timers[label][fn];
}
}
for ( ret in timers[label] ) break;
if ( !ret ) {
ret = null;
delete timers[label];
}
}
for ( ret in timers ) break;
if ( !ret )
jQuery.removeData(element, this.dataKey);
}
}
}
});
jQuery(window).bind("unload", function() {
jQuery.each(jQuery.timer.global, function(index, item) {
jQuery.timer.remove(item);
});
});
......@@ -518,8 +518,8 @@ var SN = { // StatusNet
url: form.attr('action'),
data: form.serialize() + '&ajax=1',
beforeSend: function(xhr) {
form.addClass(SN.C.S.Processing)
.find('.submit')
form.find('.submit')
.addClass(SN.C.S.Processing)
.addClass(SN.C.S.Disabled)
.attr(SN.C.S.Disabled, SN.C.S.Disabled);
},
......@@ -1543,39 +1543,94 @@ var SN = { // StatusNet
});
},
PeopletagAutocomplete: function() {
$('.form_tag_user #tags').tagInput({
tags: SN.C.PtagACData,
tagSeparator: " ",
animate: false,
formatLine: function (i, e, search, matches) {
var tag = "<b>" + e.tag.substring(0, search.length) + "</b>" + e.tag.substring(search.length);
var line = $("<div/>").addClass('mode-' + e.mode);
line.append($("<div class='tagInputLineTag'>" + tag
+ " <em class='privacy_mode'>" + e.mode + "</em></div>"));
if (e.freq)
line.append("<div class='tagInputLineFreq'>" + e.freq + "</div>");
return line;
/**
* Called when a people tag edit box is shown in the interface
*
* - loads the jQuery UI autocomplete plugin
* - sets event handlers for tag completion
*
*/
PeopletagAutocomplete: function(txtBox) {
var split = function(val) {
return val.split( /\s+/ );
}
var extractLast = function(term) {
return split(term).pop();
}
// don't navigate away from the field on tab when selecting an item
txtBox.live( "keydown", function( event ) {
if ( event.keyCode === $.ui.keyCode.TAB &&
$(this).data( "autocomplete" ).menu.active ) {
event.preventDefault();
}
});
}).autocomplete({
minLength: 0,
source: function(request, response) {
// delegate back to autocomplete, but extract the last term
response($.ui.autocomplete.filter(
SN.C.PtagACData, extractLast(request.term)));
},
focus: function() {
return false;
},
select: function(event, ui) {
var terms = split(this.value);
terms.pop();
terms.push(ui.item.value);
terms.push("");
this.value = terms.join(" ");
return false;
}
}).data('autocomplete')._renderItem = function(ul, item) {
// FIXME: with jQuery UI you cannot have it highlight the match
var _l = '<a class="ptag-ac-line-tag">' + item.tag
+ ' <em class="privacy_mode">' + item.mode + '</em>'
+ '<span class="freq">' + item.freq + '</span></a>'
return $("<li/>")
.addClass('mode-' + item.mode)
.addClass('ptag-ac-line')
.data("item.autocomplete", item)
.append(_l)
.appendTo(ul);
}
},
/**
* Run setup for the ajax people tags editor
*
* - show edit button
* - set event handle for click on edit button
* - loads people tag autocompletion data if not already present
* or if it is stale.
*
*/
PeopleTags: function() {
$('.user_profile_tags .editable').append($('<button class="peopletags_edit_button"/>'));
$('.peopletags_edit_button').live('click', function() {
var form = $(this).parents('dd').eq(0).find('form');
// We can buy time from the above animation
if (typeof SN.C.PtagACData === 'undefined') {
$.getJSON(_peopletagAC + '?token=' + $('#token').val(), function(data) {
$.ajax({
url: _peopletagAC,
dataType: 'json',
data: {token: $('#token').val()},
ifModified: true,
success: function(data) {
// item.label is used to match
for (i=0; i < data.length; i++) {
data[i].label = data[i].tag;
}
SN.C.PtagACData = data;
_loadTagInput(SN.Init.PeopletagAutocomplete);
});
} else { _loadTagInput(SN.Init.PeopletagAutocomplete); }
SN.Init.PeopletagAutocomplete(form.find('#tags'));
}
});
$(this).parents('ul').eq(0).fadeOut(200, function() {form.fadeIn(200).find('input#tags')});
})
});
$('.user_profile_tags form .submit').live('click', function() {
SN.U.FormPeopletagsXHR($(this).parents('form')); return false;
......
This diff is collapsed.
......@@ -330,9 +330,7 @@ class Action extends HTMLOutputter // lawsuit
$this->script('geometa.js');
}
$this->inlineScript('function _loadTagInput(init) { $.getScript("'.common_path('js/jquery.timers.js') .
'"); $.getScript("'.common_path('js/jquery.tagInput.js').'", init); } var _peopletagAC = "' .
$this->inlineScript('var _peopletagAC = "' .
common_local_url('peopletagautocomplete') . '";');
$this->showScriptMessages();
// Frame-busting code to avoid clickjacking attacks.
......
......@@ -1915,31 +1915,29 @@ min-width:0;
/* tag autocomplete */
.tagInputDiv {
display: none;
position: absolute;
overflow: auto;
margin-top:-1px;
z-index: 99;
}
.tagInputLine {
.ptag-ac-line {
font-weight: normal;
padding:4px;
background-color: white;
}
.ptag-ac-line:nth-child(odd) {
background-color: #f1f1f1;
}
.tagInputLineTag {
.ptag-ac-line-tag {
min-width: 150px;
display: inline-block;
}
.tagInputLineFreq {
.ptag-ac-line .freq {
min-width: 50px;
text-align: right;
display: inline-block;
float:right;
}
.ptag-ac-line.mode-public .privacy_mode {
display:none;
}
.inline-attachment img {
/* Why on earth is this changed to block at the top? */
display: inline;
......
......@@ -2173,46 +2173,30 @@ background-position: 0px -1978px;
/* tag autocomplete */
.tagInputDiv {
display: none;
position: absolute;
background-color:#f1f1f1;
overflow: auto;
margin-top:-1px;
z-index: 99;
}
.tagInputLine {
.ptag-ac-line {
font-weight: normal;
padding:4px;
background-color: white;
min-height:30px;
}
.ptag-ac-line:nth-child(odd) {
background-color: #fafafa;
}
.tagInputLineTag {
.ptag-ac-line-tag {
min-width: 150px;
display: inline-block;
}
.tagInputLineFreq {
.ptag-ac-line .freq {
min-width: 50px;
text-align: right;
display: inline-block;
float:right;
}
.tagInputDiv {
background-color: white;
border: 1px solid lightgray;
}
.tagInputDiv .mode-public .privacy_mode {
.ptag-ac-line.mode-public .privacy_mode {
display:none;
}
.tagInputSel {
background-color: gray;
color:white;
}
/*end of @media screen, projection, tv*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment