(function (Q, $) {
/**
* Streams Tools
* @module Streams-tools
* @main
*/
/**
* Interface for selecting an app user
* @class Streams userChooser
* @constructor
* @param {Object} [options] this object contains function parameters
* @param {Q.Event} [options.onChoose] is triggered with (userId, avatar)
* parameters when a user is chosen
* @param {Number} [options.delay=500] how long to delay before sending a request
* to allow more characters to be entered
* @param {Object} [options.exclude] hash of {userId: true},
* where userId are the ids of the users to exclude from the results.
* Defaults to id of logged-in user, if logged in.
*/
Q.Tool.define("Streams/userChooser", function(o) {
Q.plugins.Streams.cache = Q.plugins.Streams.cache || {};
Q.plugins.Streams.cache.userChooser = Q.plugins.Streams.cache.userChooser || {};
var tool = this;
tool.onChoose = o.onChoose;
tool.delay = o.delay;
tool.exclude = o.exclude;
var element = $(this.element);
this.$input = $('input', element);
var cached = {};
var focusedResults = false;
tool.$results = $('<div style="text-align: left;" class="Streams_userChooser_results" />')
.css({
display: 'none',
position: 'absolute',
left: tool.$input.offset().left + 'px',
top: tool.$input.offset().top + tool.$input.outerHeight() + 'px',
width: tool.$input.outerWidth(),
'z-index': 80000,
background: 'white',
border: 'solid 1px #99a',
'tab-index': 9000
}).on(Q.Pointer.start.eventName + ' focusin', function () {
focusedResults = true;
}).appendTo('body');
var t = null;
tool.$input.on('blur', function (event) {
setTimeout(function () {
if (!focusedResults) {
tool.$results.remove();
} else {
function _handlePointerEnd() {
tool.$results.remove();
$(document).off(Q.Pointer.end, _handlePointerEnd);
}
$(document).on(Q.Pointer.end, tool, function () {
setTimeout(_handlePointerEnd, 0);
});
}
focusedResults = false;
}, 10);
}).on('focus change', doQuery);
element.on('keyup keydown', doQuery);
var lastQuery = null;
function doQuery(event) {
var cur = $('.Q_selected', tool.$results);
var query = tool.$input.val();
if (query === lastQuery) {
return;
}
lastQuery = query;
switch (event.keyCode) {
case 38: // up arrow
if (event.type === 'keyup') {
return;
}
var prev = cur.prev();
if (!prev.length) {
prev = tool.$results.children().last();
}
tool.$results.children().removeClass('Q_selected');
prev.addClass('Q_selected');
return false;
case 40: // down arrow
if (event.type === 'keyup') {
return;
}
var next = cur.next();
if (!next.length) {
next = tool.$results.children().first();
}
tool.$results.children().removeClass('Q_selected');
next.addClass('Q_selected');
return false;
case 13: // enter
if (event.type === 'keyup') {
return;
}
if (cur) {
onChoose(cur);
}
return false;
default:
if (event.type === 'keydown') {
return;
}
if (!query) {
tool.$results.remove();
return;
}
tool.$input.css({
'background-image': 'url(' +Q.url('/{{Q}}/img/throbbers/loading.gif') + ')',
'background-repeat': 'no-repeat'
});
Q.Streams.Avatar.byPrefix(tool.$input.val().toLowerCase(), onResponse, {'public': true});
}
function onChoose (cur) {
var userId = cur.data('userId');
var avatar = cur.data('avatar');
tool.$input.blur().val('');
Q.handle(tool.onChoose, this, [userId, avatar]);
tool.end();
}
function onResponse (err, avatars) {
tool.$input.css('background-image', 'none');
if (err) {
return; // silently return
}
if (Q.isEmpty(avatars)) {
return tool.$results.remove();
}
tool.$results.empty();
var show = 0;
for (var k in avatars) {
if (k in tool.exclude && tool.exclude[k]) {
continue;
}
var result = $('<a class="Q_selectable" style="display: block;" />').append(
$('<img style="vertical-align: middle; width: 40px; height: 40px;" />')
.attr('src', Q.plugins.Users.iconUrl(avatars[k].icon, 40))
).append(
$('<span />').html(avatars[k].displayName())
).on(Q.Pointer.enter, function () {
$('*', tool.$results).removeClass('Q_selected');
$(this).addClass('Q_selected');
}).on(Q.Pointer.leave, function () {
$('*', tool.$results).removeClass('Q_selected');
$(this).addClass('Q_selected');
}).on(Q.Pointer.fastclick, function () {
onChoose($(this));
}).data('userId', k)
.data('avatar', avatars[k])
.on(Q.Pointer.start.eventName + ' focusin', function () {
focusedResults = true;
}).appendTo(tool.$results);
if (!show) {
result.addClass('Q_selected');
}
++show;
}
if (show) {
tool.$results.css({
left: tool.$input.offset().left + 'px',
top: tool.$input.offset().top + tool.$input.outerHeight() + 'px',
width: tool.$input.outerWidth()
}).appendTo('body').show();
} else {
tool.$results.remove();
}
}
}
},
{
onChoose: new Q.Event(),
delay: 500,
exclude: {}
},
{
end: function () {
this.$input.blur().trigger('Q_refresh');
this.$results.remove();
}
}
);
})(Q, jQuery);