Show:

File: platform/plugins/Users/web/js/tools/friendSelector.js

(function (Q, $) {

/**
 * Users Tools
 * @module Users-tools
 * @main
 */

/**
 * Allows selecting a facebook friend from the logged-in user's friends list.
 * @class Users friendSelector
 * @constructor
 * @param {Object} [options] this object contains function parameters
 *   @param {Function} [options.onSelect] This callback is called when the user selects a friend.
 *   @required
 *   @param {Array|Object|Function} [options.customList]
 *   Optional. By default friends list is fetched from facebook, but here you can provide an array of friends or
 *   callback which in turn will call friendSelector callback passing it such array as first agrument.
 *   Callback may be a function or string name of the function.
 *   Array should contain objects like <code> { id: 'id', name: 'name' } </code>.
 *   <b>'includeMe' option is ignored if 'customList' provided </b>
 *   @param {String|Boolean} [options.includeMe]
 *   Whether or not to include user himself. Can be just boolean true or a string,
 *    which is used instead of user real name.
 *    <b>Ignored if 'customList' option is provided.</b>
 *    @param {String} [options.platform]
 *    Has to be "facebook" for now.
 *    @default 'facebook'
 *    @param {String|Boolean} [options.prompt]
 *    Specifies type of prompt if user is not logged in or didn't give required permission for the tool.
 *    Can be either 'button', 'dialog' or null|false. In first case just shows simple button which opens facebook login popup.
 *    In second case shows Users.facebookDialog prompting user to login.
 *    In third case will not show any prompt and will just hide the tool.
 *    @optional
 *    @param {String} [options.promptTitle]
 *    Used only when 'prompt' equals 'dialog' - will be title of the dialog.
 *    @optional
 *    @param {String} [options.promptText]
 *    Used either for button caption when 'prompt' equals 'button' or
 *                 dialog text when 'prompt' equals 'dialog'.
 *    @optional
 *    @param {Function} [options.filter] Custom function to filter out the friends list.
 *    @param {Function} [options.ordering] Custom function to order the friends list. By default friends are ordered by name.
 */
Q.Tool.define('Users/friendSelector', function(o) {
	var toolDiv = $(this.element);
	if (!o.onSelect)
	{
		alert("Please provide the onSelect option for the friendSelector");
		return false;
	}
	if (o.platform !== 'facebook')
	{
		alert("Only facebook is supported as a platform for now");
		return false;
	}
	o.onSelect = new Q.Event(o.onSelect);
	
	function onSuccessfulLogin()
	{
		if (o.customList)
		{
			if (typeof(o.customList) == 'string') // string name of callback
				eval(o.customList)(processFriends);
			else if (typeof(o.customList) == 'function') // just regular callback
				o.customList(processFriends);
			else // an array
				processFriends(o.customList);
		}
		else
		{
			FB.api('me/friends', function(response)
			{
				var friends = response.data;
				if (o.includeMe)
				{
					FB.api('me', function(response)
					{
						friends.unshift({
							'id': response.id,
							'name': (typeof(o.includeMe) == 'string' ? o.includeMe : response.first_name + ' ' + response.last_name)
						});
						processFriends(friends);
					});
				}
				else
				{
					processFriends(friends);
				}
			});
		}
	}
	
	function processFriends(friends)
	{
		toolDiv.empty();
		friends = o.filter(friends);
		friends = o.ordering(friends);
		
		toolDiv.append('<div class="Users_friendSelector_tool_title">Select a user:</div>');
		var filterField = $('<div class="Users_friendSelector_tool_input_field" />');
		var filterFieldInput = $('<input type="text" placeholder="Start typing..." />');
		filterFieldInput.keyup(function()
		{
			fillFriends(o.filter(friends, $(this).val()));
		});
		filterField.prepend(filterFieldInput);
		toolDiv.append(filterField);
		var filterFieldWidth = toolDiv.width() - parseInt(filterFieldInput.css('padding-left')) -
												parseInt(filterFieldInput.css('padding-right'));
		filterFieldInput.css({ 'width': filterFieldWidth + 'px' });
		
		var searchIcon = $('<div class="Users_friendSelector_search_icon" />');
		$(document.body).append(searchIcon);
		var iconLeft = filterField.offset().left + filterField.outerWidth() - searchIcon.width();
		var iconTop = filterField.offset().top + (filterField.innerHeight() - searchIcon.height()) / 2;
		searchIcon.css({
			'margin-left': iconLeft + 'px',
			'margin-top': iconTop + 'px'
		});
		
		toolDiv.plugin('Q/placeholders');
		
		fillFriends(friends);
	}
	
	function fillFriends(friends)
	{
		$('.Users_friendSelector_tool > ul').remove();
		var friendsList = $('<ul />'), i;
		for (i in friends)
		{
			var friendItem = $(
				'<li data-uid="'+ friends[i].id + '">' +
					'<div class="Users_friendSelector_tool_user_picture">' +
						'<img src="https://graph.facebook.com/' + friends[i].id + '/picture" alt="User picture" />' +
					 '</div>' +
					 '<div class="Users_friendSelector_tool_user_name">' + friends[i].name + '</div>' +
				 '</li>'
			);
			friendItem.click(function() {
				Q.handle(options.onSelect, this, [$(this).attr('data-uid')]);
			});
			friendsList.append(friendItem);
			}
		$('.Users_friendSelector_tool').append(friendsList);
	}
	
	switch (o.platform) {
		case 'facebook':
			toolDiv.empty().append('<div class="Users_tools_throbber"><img src="' + Q.url('/{{Q}}/img/throbbers/loading.gif') + '" alt="" /></div>');
			
			Users.login({
				tryQuietly: true,
				using: 'facebook',
				onSuccess: function()
				{
					onSuccessfulLogin(toolDiv);
				},
				onCancel: function()
				{
					// we may show the dialog asking user to login
					if (o.prompt == 'dialog')
					{
						Users.facebookDialog({
							'title': o.promptTitle,
							'content': o.promptText,
							'buttons': [
								{
									'label': 'Login',
									'handler': function(dialog)
									{
										Users.login(
										{
											using: 'facebook',
											onCancel: function()
											{
												dialog.close();
												toolDiv.hide();
											},
											onSuccess: function()
											{
												dialog.close();
												onSuccessfulLogin(toolDiv);
											}
										});
									},
									'default': true
								},
								{
									'label': 'Cancel',
									'handler': function(dialog)
									{
										toolDiv.hide();
										dialog.close();
									}
								}
							],
							'position': null,
							'shadow': true
						});
					}
					// or a button, clicking on it will cause facebook login popup to appear
					else if (o.prompt == 'button')
					{
						var button = $('<button class="Q_button">' + o.promptText + '</button>');
						toolDiv.empty().append(button);
						button.click(function()
						{
							Users.login(
							{
								using: 'facebook',
								onSuccess: function()
								{
									onSuccessfulLogin();
								}
							});
						});
					}
					// or just hide friend selector
					else
					{
						toolDiv.hide();
						Users.login.options.onSuccess.set(function() {
							Users.login.options.onSuccess.remove('friend-selector-login');
							toolDiv.show();
							onSuccessfulLogin();
						}, 'friend-selector-login');
					}
				}
			});
		break;
	}
}, 

{
	onSelect: null,
	customList: null,
	includeMe: false,
	platform: 'facebook',
	prompt: false,
	promptTitle: 'Login required',
	promptText: 'Please log into Facebook to to view your friends.',
	filter: function(friends, filter)
	{
		if (typeof(filter) == 'undefined')
		{
			return friends;
		}
		else
		{
			var filteredFriends = [], i, j, k;
			for (i in friends)
			{
				var filterWords = filter.toLowerCase().split(' ');
				var nameWords = friends[i].name.toLowerCase().split(' ');
				var passedChecks = [];
				for (j in filterWords)
				{
					for (k in nameWords)
					{
						if (nameWords[k].indexOf(filterWords[j]) != -1)
						{
							passedChecks.push(true);
							delete nameWords[k];
							break;
						}
					}
				}
				var passed = passedChecks.length == filterWords.length;
				for (j in passedChecks)
				{
					if (!passedChecks[j])
						passed = false;
				}
				if (passed)
					filteredFriends.push(friends[i]);
			}
			return filteredFriends;
		}
	},
	ordering: function(friends) { return friends; }
}

);

})(Q, jQuery);