diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb
index 324b1a9f0..fb73151ac 100644
--- a/ruby/lib/jam_ruby/models/search.rb
+++ b/ruby/lib/jam_ruby/models/search.rb
@@ -22,6 +22,20 @@ module JamRuby
self.text_search({ SEARCH_TEXT_TYPE_ID => :musicians, :query => txt }, user)
end
+ def self.session_invite_search(query, user)
+ srch = Search.new
+ srch.search_type = :session_invite
+ like_str = "%#{query.downcase}%"
+ rel = User
+ .musicians
+ .where(["users.id IN (SELECT friend_id FROM friendships WHERE user_id = '#{user.id}')"])
+ .where(["first_name ILIKE ? OR last_name ILIKE ?", like_str, like_str])
+ .limit(10)
+ .order([:last_name, :first_name])
+ srch.results = rel.all
+ srch
+ end
+
def self.text_search(params, user = nil)
srch = Search.new
unless (params.blank? || params[:query].blank? || 2 > params[:query].length)
@@ -72,11 +86,12 @@ module JamRuby
args
end
+ PARAM_SESSION_INVITE = :srch_sessinv
PARAM_MUSICIAN = :srch_m
PARAM_BAND = :srch_b
PARAM_FEED = :srch_f
- F_PER_PAGE = B_PER_PAGE = M_PER_PAGE = 10
+ F_PER_PAGE = B_PER_PAGE = M_PER_PAGE = 20
M_MILES_DEFAULT = 500
B_MILES_DEFAULT = 0
@@ -205,6 +220,10 @@ module JamRuby
public
+ def session_invite_search?
+ :session_invite == @search_type
+ end
+
def musicians_text_search?
:musicians == @search_type
end
diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb
index 327e790b2..1c4f49700 100644
--- a/ruby/lib/jam_ruby/models/user.rb
+++ b/ruby/lib/jam_ruby/models/user.rb
@@ -1091,8 +1091,8 @@ module JamRuby
end
def top_followings
- @topf ||= User.joins("INNER JOIN follows ON follows.followable_id = users.id")
- .where(['follows.user_id = ?',self.id])
+ @topf ||= User.joins("INNER JOIN follows ON follows.followable_id = users.id AND follows.followable_type = '#{self.class.to_s}'")
+ .where(['follows.user_id = ?', self.id])
.order('follows.created_at DESC')
.limit(3)
end
diff --git a/ruby/spec/jam_ruby/models/search_spec.rb b/ruby/spec/jam_ruby/models/search_spec.rb
index 1f6689f45..21fbe8d42 100644
--- a/ruby/spec/jam_ruby/models/search_spec.rb
+++ b/ruby/spec/jam_ruby/models/search_spec.rb
@@ -33,10 +33,24 @@ describe Search do
end
- it "search for band & musician " do
- create_peachy_data
+ # it "search for band & musician " do
+ # create_peachy_data
+ # assert_peachy_data
+ # end
- assert_peachy_data
+ let(:user1) { FactoryGirl.create(:user, :first_name => Faker::Name.first_name, :last_name => Faker::Name.last_name) }
+ let(:user2) { FactoryGirl.create(:user, :first_name => Faker::Name.first_name, :last_name => Faker::Name.last_name) }
+ let(:user3) { FactoryGirl.create(:user, :first_name => Faker::Name.first_name, :last_name => Faker::Name.last_name) }
+
+ it 'find autocomplete friend musicians' do
+ Friendship.save_using_models(user1, user2)
+ Friendship.save_using_models(user1, user3)
+
+ srch = Search.session_invite_search(user1.first_name[0..3], user2)
+ expect(srch.results.size).to eq(1)
+
+ srch = Search.session_invite_search(user1.last_name[0..3], user2)
+ expect(srch.results.size).to eq(1)
end
end
diff --git a/web/app/assets/javascripts/createSession.js.erb b/web/app/assets/javascripts/createSession.js.erb
index 4ea254cba..c591b88b4 100644
--- a/web/app/assets/javascripts/createSession.js.erb
+++ b/web/app/assets/javascripts/createSession.js.erb
@@ -35,8 +35,12 @@
var genre = sessionSettings.hasOwnProperty('genres') && sessionSettings.genres.length > 0 ? sessionSettings.genres[0].id : '';
context.JK.GenreSelectorHelper.reset('#create-session-genre', genre);
- var musician_access = sessionSettings.hasOwnProperty('musician_access') ? sessionSettings.musician_access : true;
+ var bandId = sessionSettings.hasOwnProperty('band_id') ? sessionSettings.band_id : '';
+ $('#band-list', $form).val(bandId);
+
+ var musician_access = sessionSettings.hasOwnProperty('musician_access') ? sessionSettings.musician_access : false;
$('#musician-access option[value=' + musician_access + ']').attr('selected', 'selected');
+
toggleMusicianAccess();
if (musician_access) {
@@ -44,10 +48,7 @@
$('#musician-access-option-' + approval_required).iCheck('check').attr('checked', 'checked');
}
- var bandId = sessionSettings.hasOwnProperty('band_id') ? sessionSettings.band_id : '';
- $('#band-list', $form).val(bandId);
-
- var fan_access = sessionSettings.hasOwnProperty('fan_access') ? sessionSettings.fan_access : true;
+ var fan_access = sessionSettings.hasOwnProperty('fan_access') ? sessionSettings.fan_access : false;
$('#fan-access option[value=' + fan_access + ']').attr('selected', 'selected');
toggleFanAccess();
@@ -56,11 +57,13 @@
$('#fan-chat-option-' + fan_chat).iCheck('check').attr('checked', 'checked');
}
+ context.JK.dropdown($('#musician-access', $form));
+ context.JK.dropdown($('#fan-access', $form));
+
$('#friend-input')
.unbind('blur')
.attr("placeholder", "Looking up friends...")
.prop('disabled', true)
- // Should easily be able to grab other items out of sessionSettings and put them into the appropriate ui elements.
}
function validateForm() {
@@ -216,11 +219,11 @@
var value = $("#musician-access option:selected").val();
if (value == "false") {
$("input[name='musician-access-option']").attr('disabled', 'disabled');
- $("input[name='musician-access-option']").parent().addClass("op50");
+ $("input[name='musician-access-option']").parent().addClass("op10");
}
else {
$("input[name='musician-access-option']").removeAttr('disabled');
- $("input[name='musician-access-option']").parent().removeClass("op50");
+ $("input[name='musician-access-option']").parent().removeClass("op10");
}
}
@@ -228,11 +231,11 @@
var value = $("#fan-access option:selected").val();
if (value == "false") {
$("input[name='fan-chat-option']").attr('disabled', 'disabled');
- $("input[name='fan-chat-option']").parent().addClass("op50");
+ $("input[name='fan-chat-option']").parent().addClass("op10");
}
else {
$("input[name='fan-chat-option']").removeAttr('disabled');
- $("input[name='fan-chat-option']").parent().removeClass("op50");
+ $("input[name='fan-chat-option']").parent().removeClass("op10");
}
}
@@ -264,8 +267,7 @@
}
function sessionSettingsLoaded(response) {
- if (response != null)
- {
+ if (response != null) {
sessionSettings = response;
}
resetForm();
diff --git a/web/app/assets/javascripts/findBand.js b/web/app/assets/javascripts/findBand.js
index 024d3fab8..144bf4541 100644
--- a/web/app/assets/javascripts/findBand.js
+++ b/web/app/assets/javascripts/findBand.js
@@ -200,7 +200,7 @@
$('#band_genre').change(refreshDisplay);
$('#band_order_by').change(refreshDisplay);
- $('#band-filter-results').bind('scroll', function() {
+ $('#band-filter-results').closest('.content-body-scroller').bind('scroll', function() {
if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) {
if (page_num < page_count) {
page_num += 1;
diff --git a/web/app/assets/javascripts/findMusician.js b/web/app/assets/javascripts/findMusician.js
index b02074fc5..e96bb7329 100644
--- a/web/app/assets/javascripts/findMusician.js
+++ b/web/app/assets/javascripts/findMusician.js
@@ -222,7 +222,7 @@
$('#musician_instrument').change(refreshDisplay);
$('#musician_order_by').change(refreshDisplay);
- $('#musician-filter-results').bind('scroll', function() {
+ $('#musician-filter-results').closest('.content-body-scroller').bind('scroll', function() {
if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) {
if (page_num < page_count) {
page_num += 1;
diff --git a/web/app/assets/javascripts/hoverBand.js b/web/app/assets/javascripts/hoverBand.js
index ecdfaa860..fc6ca414c 100644
--- a/web/app/assets/javascripts/hoverBand.js
+++ b/web/app/assets/javascripts/hoverBand.js
@@ -26,9 +26,11 @@
musicianHtml += '
' + val.name + ' | ';
instrumentHtml = '';
- $.each(val.instruments, function(index, instrument) {
- instrumentHtml += '  ';
- });
+ if (val.instruments) { // @FIXME: edge case for Test user that has no instruments?
+ $.each(val.instruments, function(index, instrument) {
+ instrumentHtml += '  ';
+ });
+ }
instrumentHtml += ' | ';
diff --git a/web/app/assets/javascripts/inviteMusicians.js b/web/app/assets/javascripts/inviteMusicians.js
index 36a11a465..99400a2c9 100644
--- a/web/app/assets/javascripts/inviteMusicians.js
+++ b/web/app/assets/javascripts/inviteMusicians.js
@@ -67,15 +67,16 @@
var autoCompleteOptions = {
lookup: { suggestions: userNames, data: userIds },
- onSelect: addInvitation
+ onSelect: addInvitation,
+ serviceUrl: '/api/search.json?srch_sessinv=1',
+ minChars: 3,
};
$('#friend-input').attr("placeholder", "Type a friend\'s name").prop('disabled', false);
if (!autoComplete) {
autoComplete = $('#friend-input').autocomplete(autoCompleteOptions);
- }
- else {
+ } else {
autoComplete.setOptions(autoCompleteOptions);
}
@@ -100,6 +101,10 @@
}
function addInvitation(value, data) {
+ if (undefined === data) {
+ data = value.data;
+ value = value.value;
+ }
if (0 > invitedFriends.indexOf(data)) {
var template = $('#template-added-invitation').html();
var imgStyle = _inviteExists(data) ? 'display:none' : '';
diff --git a/web/app/assets/javascripts/jquery.autocomplete.js b/web/app/assets/javascripts/jquery.autocomplete.js
index da94f65bf..4346e6f5d 100644
--- a/web/app/assets/javascripts/jquery.autocomplete.js
+++ b/web/app/assets/javascripts/jquery.autocomplete.js
@@ -1,433 +1,823 @@
/**
-* Ajax Autocomplete for jQuery, version 1.1.5
-* (c) 2010 Tomas Kirda, Vytautas Pranskunas
+* Ajax Autocomplete for jQuery, version 1.2.9
+* (c) 2013 Tomas Kirda
*
* Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
-* For details, see the web site: http://www.devbridge.com/projects/autocomplete/jquery/
+* For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete
*
-* Last Review: 07/24/2012
*/
-/*jslint onevar: true, evil: true, nomen: true, eqeqeq: true, bitwise: true, regexp: true, newcap: true, immed: true */
-/*global window: true, document: true, clearInterval: true, setInterval: true, jQuery: true */
+/*jslint browser: true, white: true, plusplus: true */
+/*global define, window, document, jQuery */
-(function ($) {
+// Expose plugin as an AMD module if AMD loader is present:
+(function (factory) {
+ 'use strict';
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['jquery'], factory);
+ } else {
+ // Browser globals
+ factory(jQuery);
+ }
+}(function ($) {
+ 'use strict';
- var reEscape = new RegExp('(\\' + ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\'].join('|\\') + ')', 'g');
+ var
+ utils = (function () {
+ return {
+ escapeRegExChars: function (value) {
+ return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
+ },
+ createNode: function (containerClass) {
+ var div = document.createElement('div');
+ div.className = containerClass;
+ div.style.position = 'absolute';
+ div.style.display = 'none';
+ return div;
+ }
+ };
+ }()),
- function fnFormatResult(value, data, currentValue) {
- var pattern = '(' + currentValue.replace(reEscape, '\\$1') + ')';
- return value.replace(new RegExp(pattern, 'gi'), '$1<\/strong>');
- }
+ keys = {
+ ESC: 27,
+ TAB: 9,
+ RETURN: 13,
+ LEFT: 37,
+ UP: 38,
+ RIGHT: 39,
+ DOWN: 40
+ };
- function Autocomplete(el, options) {
- this.el = $(el);
- this.el.attr('autocomplete', 'off');
- this.suggestions = [];
- this.data = [];
- this.badQueries = [];
- this.selectedIndex = -1;
- this.currentValue = this.el.val();
- this.intervalId = 0;
- this.cachedResponse = [];
- this.onChangeInterval = null;
- this.onChange = null;
- this.ignoreValueChange = false;
- this.serviceUrl = options.serviceUrl;
- this.isLocal = false;
- this.options = {
- autoSubmit: false,
- minChars: 1,
- maxHeight: 300,
- deferRequestBy: 0,
- width: 0,
- highlight: true,
- params: {},
- fnFormatResult: fnFormatResult,
- delimiter: null,
- zIndex: 9999
- };
- this.initialize();
- this.setOptions(options);
- this.el.data('autocomplete', this);
- }
+ function Autocomplete(el, options) {
+ var noop = function () { },
+ that = this,
+ defaults = {
+ autoSelectFirst: false,
+ appendTo: 'body',
+ serviceUrl: null,
+ lookup: null,
+ onSelect: null,
+ width: 'auto',
+ minChars: 1,
+ maxHeight: 300,
+ deferRequestBy: 0,
+ params: {},
+ formatResult: Autocomplete.formatResult,
+ delimiter: null,
+ zIndex: 9999,
+ type: 'GET',
+ noCache: false,
+ onSearchStart: noop,
+ onSearchComplete: noop,
+ onSearchError: noop,
+ containerClass: 'autocomplete-suggestions',
+ tabDisabled: false,
+ dataType: 'text',
+ currentRequest: null,
+ triggerSelectOnValidInput: true,
+ lookupFilter: function (suggestion, originalQuery, queryLowerCase) {
+ return suggestion.value.toLowerCase().indexOf(queryLowerCase) !== -1;
+ },
+ paramName: 'query',
+ transformResult: function (response) {
+ return typeof response === 'string' ? $.parseJSON(response) : response;
+ }
+ };
- $.fn.autocomplete = function (options, optionName) {
+ // Shared variables:
+ that.element = el;
+ that.el = $(el);
+ that.suggestions = [];
+ that.badQueries = [];
+ that.selectedIndex = -1;
+ that.currentValue = that.element.value;
+ that.intervalId = 0;
+ that.cachedResponse = {};
+ that.onChangeInterval = null;
+ that.onChange = null;
+ that.isLocal = false;
+ that.suggestionsContainer = null;
+ that.options = $.extend({}, defaults, options);
+ that.classes = {
+ selected: 'autocomplete-selected',
+ suggestion: 'autocomplete-suggestion'
+ };
+ that.hint = null;
+ that.hintValue = '';
+ that.selection = null;
- var autocompleteControl;
+ // Initialize and set options:
+ that.initialize();
+ that.setOptions(options);
+ }
- if (typeof options == 'string') {
- autocompleteControl = this.data('autocomplete');
- if (typeof autocompleteControl[options] == 'function') {
- autocompleteControl[options](optionName);
- }
- } else {
- autocompleteControl = new Autocomplete(this.get(0) || $(''), options);
- }
- return autocompleteControl;
- };
+ Autocomplete.utils = utils;
+ $.Autocomplete = Autocomplete;
- Autocomplete.prototype = {
+ Autocomplete.formatResult = function (suggestion, currentValue) {
+ var pattern = '(' + utils.escapeRegExChars(currentValue) + ')';
- killerFn: null,
+ return suggestion.value.replace(new RegExp(pattern, 'gi'), '$1<\/strong>');
+ };
- initialize: function () {
+ Autocomplete.prototype = {
- var me, uid, autocompleteElId;
- me = this;
- uid = Math.floor(Math.random() * 0x100000).toString(16);
- autocompleteElId = 'Autocomplete_' + uid;
+ killerFn: null,
- this.killerFn = function (e) {
- if ($(e.target).parents('.autocomplete').size() === 0) {
- me.killSuggestions();
- me.disableKillerFn();
- }
- };
+ initialize: function () {
+ var that = this,
+ suggestionSelector = '.' + that.classes.suggestion,
+ selected = that.classes.selected,
+ options = that.options,
+ container;
- if (!this.options.width) { this.options.width = this.el.width(); }
- this.mainContainerId = 'AutocompleteContainter_' + uid;
+ // Remove autocomplete attribute to prevent native suggestions:
+ that.element.setAttribute('autocomplete', 'off');
- $('').appendTo('body');
+ that.killerFn = function (e) {
+ if ($(e.target).closest('.' + that.options.containerClass).length === 0) {
+ that.killSuggestions();
+ that.disableKillerFn();
+ }
+ };
- this.container = $('#' + autocompleteElId);
- this.fixPosition();
- if (window.opera) {
- this.el.keypress(function (e) { me.onKeyPress(e); });
- } else {
- this.el.keydown(function (e) { me.onKeyPress(e); });
- }
- this.el.keyup(function (e) { me.onKeyUp(e); });
- this.el.blur(function () { me.enableKillerFn(); });
- this.el.focus(function () { me.fixPosition(); });
- this.el.change(function () { me.onValueChanged(); });
- },
+ that.suggestionsContainer = Autocomplete.utils.createNode(options.containerClass);
- extendOptions: function (options) {
- $.extend(this.options, options);
- },
+ container = $(that.suggestionsContainer);
- setOptions: function (options) {
- var o = this.options;
- this.extendOptions(options);
- if (o.lookup || o.isLocal) {
- this.isLocal = true;
- if ($.isArray(o.lookup)) { o.lookup = { suggestions: o.lookup, data: [] }; }
- }
- $('#' + this.mainContainerId).css({ zIndex: o.zIndex });
- this.container.css({ maxHeight: o.maxHeight + 'px', width: o.width });
- },
+ container.appendTo(options.appendTo);
- clearCache: function () {
- this.cachedResponse = [];
- this.badQueries = [];
- },
+ // Only set width if it was provided:
+ if (options.width !== 'auto') {
+ container.width(options.width);
+ }
- disable: function () {
- this.disabled = true;
- },
+ // Listen for mouse over event on suggestions list:
+ container.on('mouseover.autocomplete', suggestionSelector, function () {
+ that.activate($(this).data('index'));
+ });
- enable: function () {
- this.disabled = false;
- },
+ // Deselect active element when mouse leaves suggestions container:
+ container.on('mouseout.autocomplete', function () {
+ that.selectedIndex = -1;
+ container.children('.' + selected).removeClass(selected);
+ });
- fixPosition: function () {
- var offset = this.el.offset();
- $('#' + this.mainContainerId).css({ top: (offset.top + this.el.innerHeight()) + 'px', left: offset.left + 'px' });
- },
+ // Listen for click event on suggestions list:
+ container.on('click.autocomplete', suggestionSelector, function () {
+ that.select($(this).data('index'));
+ });
- enableKillerFn: function () {
- var me = this;
- $(document).bind('click', me.killerFn);
- },
+ that.fixPosition();
- disableKillerFn: function () {
- var me = this;
- $(document).unbind('click', me.killerFn);
- },
+ that.fixPositionCapture = function () {
+ if (that.visible) {
+ that.fixPosition();
+ }
+ };
- killSuggestions: function () {
- var me = this;
- this.stopKillSuggestions();
- this.intervalId = window.setInterval(function () { me.hide(); me.stopKillSuggestions(); }, 300);
- },
+ $(window).on('resize.autocomplete', that.fixPositionCapture);
- stopKillSuggestions: function () {
- window.clearInterval(this.intervalId);
- },
+ that.el.on('keydown.autocomplete', function (e) { that.onKeyPress(e); });
+ that.el.on('keyup.autocomplete', function (e) { that.onKeyUp(e); });
+ that.el.on('blur.autocomplete', function () { that.onBlur(); });
+ that.el.on('focus.autocomplete', function () { that.onFocus(); });
+ that.el.on('change.autocomplete', function (e) { that.onKeyUp(e); });
+ },
- onValueChanged: function () {
- this.change(this.selectedIndex);
- },
+ onFocus: function () {
+ var that = this;
+ that.fixPosition();
+ if (that.options.minChars <= that.el.val().length) {
+ that.onValueChange();
+ }
+ },
- onKeyPress: function (e) {
- if (this.disabled || !this.enabled) { return; }
- // return will exit the function
- // and event will not be prevented
- switch (e.keyCode) {
- case 27: //KEY_ESC:
- this.el.val(this.currentValue);
- this.hide();
- break;
- case 9: //KEY_TAB:
- case 13: //KEY_RETURN:
- if (this.selectedIndex === -1) {
- this.hide();
- return;
- }
- this.select(this.selectedIndex);
- if (e.keyCode === 9) { return; }
- break;
- case 38: //KEY_UP:
- this.moveUp();
- break;
- case 40: //KEY_DOWN:
- this.moveDown();
- break;
- default:
- return;
- }
- e.stopImmediatePropagation();
- e.preventDefault();
- },
+ onBlur: function () {
+ this.enableKillerFn();
+ },
- onKeyUp: function (e) {
- if (this.disabled) { return; }
- switch (e.keyCode) {
- case 38: //KEY_UP:
- case 40: //KEY_DOWN:
- return;
- }
- clearInterval(this.onChangeInterval);
- if (this.currentValue !== this.el.val()) {
- if (this.options.deferRequestBy > 0) {
- // Defer lookup in case when value changes very quickly:
- var me = this;
- this.onChangeInterval = setInterval(function () { me.onValueChange(); }, this.options.deferRequestBy);
- } else {
- this.onValueChange();
- }
- }
- },
+ setOptions: function (suppliedOptions) {
+ var that = this,
+ options = that.options;
- onValueChange: function () {
- clearInterval(this.onChangeInterval);
- this.currentValue = this.el.val();
- var q = this.getQuery(this.currentValue);
- this.selectedIndex = -1;
- if (this.ignoreValueChange) {
- this.ignoreValueChange = false;
- return;
- }
- if (q === '' || q.length < this.options.minChars) {
- this.hide();
- } else {
- this.getSuggestions(q);
- }
- },
+ $.extend(options, suppliedOptions);
- getQuery: function (val) {
- var d, arr;
- d = this.options.delimiter;
- if (!d) { return $.trim(val); }
- arr = val.split(d);
- return $.trim(arr[arr.length - 1]);
- },
+ that.isLocal = $.isArray(options.lookup);
- getSuggestionsLocal: function (q) {
- var ret, arr, len, val, i;
- arr = this.options.lookup;
- len = arr.suggestions.length;
- ret = { suggestions: [], data: [] };
- q = q.toLowerCase();
- for (i = 0; i < len; i++) {
- val = arr.suggestions[i];
- if (val.toLowerCase().indexOf(q) === 0) {
- ret.suggestions.push(val);
- ret.data.push(arr.data[i]);
- }
- }
- return ret;
- },
+ if (that.isLocal) {
+ options.lookup = that.verifySuggestionsFormat(options.lookup);
+ }
- getSuggestions: function (q) {
+ // Adjust height, width and z-index:
+ $(that.suggestionsContainer).css({
+ 'max-height': options.maxHeight + 'px',
+ 'width': options.width + 'px',
+ 'z-index': options.zIndex
+ });
+ },
- var cr, me;
- cr = this.isLocal ? this.getSuggestionsLocal(q) : this.cachedResponse[q]; //dadeta this.options.isLocal ||
- if (cr && $.isArray(cr.suggestions)) {
- this.suggestions = cr.suggestions;
- this.data = cr.data;
- this.suggest();
- } else if (!this.isBadQuery(q)) {
- me = this;
- me.options.params.query = q;
- $.get(this.serviceUrl, me.options.params, function (txt) { me.processResponse(txt); }, 'text');
- }
- },
+ clearCache: function () {
+ this.cachedResponse = {};
+ this.badQueries = [];
+ },
- isBadQuery: function (q) {
- var i = this.badQueries.length;
- while (i--) {
- if (q.indexOf(this.badQueries[i]) === 0) { return true; }
- }
- return false;
- },
+ clear: function () {
+ this.clearCache();
+ this.currentValue = '';
+ this.suggestions = [];
+ },
- hide: function () {
- this.enabled = false;
- this.selectedIndex = -1;
- this.container.hide();
- },
+ disable: function () {
+ var that = this;
+ that.disabled = true;
+ if (that.currentRequest) {
+ that.currentRequest.abort();
+ }
+ },
- suggest: function () {
+ enable: function () {
+ this.disabled = false;
+ },
- if (this.suggestions.length === 0) {
- this.hide();
- return;
- }
+ fixPosition: function () {
+ var that = this,
+ offset,
+ styles;
- var me, len, div, f, v, i, s, mOver, mClick;
- me = this;
- len = this.suggestions.length;
- f = this.options.fnFormatResult;
- v = this.getQuery(this.currentValue);
- mOver = function (xi) { return function () { me.activate(xi); }; };
- mClick = function (xi) { return function () { me.select(xi); }; };
- this.container.hide().empty();
- for (i = 0; i < len; i++) {
- s = this.suggestions[i];
- div = $((me.selectedIndex === i ? '' + f(s, this.data[i], v) + '
');
- div.mouseover(mOver(i));
- div.click(mClick(i));
- this.container.append(div);
- }
- this.enabled = true;
- this.container.show();
- },
+ // Don't adjsut position if custom container has been specified:
+ if (that.options.appendTo !== 'body') {
+ return;
+ }
- processResponse: function (text) {
- var response;
- try {
- response = eval('(' + text + ')');
- } catch (err) { return; }
- if (!$.isArray(response.data)) { response.data = []; }
- if (!this.options.noCache) {
- this.cachedResponse[response.query] = response;
- if (response.suggestions.length === 0) { this.badQueries.push(response.query); }
- }
- if (response.query === this.getQuery(this.currentValue)) {
- this.suggestions = response.suggestions;
- this.data = response.data;
- this.suggest();
- }
- },
+ offset = that.el.offset();
- activate: function (index) {
- var divs, activeItem;
- divs = this.container.children();
- // Clear previous selection:
- if (this.selectedIndex !== -1 && divs.length > this.selectedIndex) {
- $(divs.get(this.selectedIndex)).removeClass();
- }
- this.selectedIndex = index;
- if (this.selectedIndex !== -1 && divs.length > this.selectedIndex) {
- activeItem = divs.get(this.selectedIndex);
- $(activeItem).addClass('selected');
- }
- return activeItem;
- },
+ styles = {
+ top: (offset.top + that.el.outerHeight()) + 'px',
+ left: offset.left + 'px'
+ };
- deactivate: function (div, index) {
- div.className = '';
- if (this.selectedIndex === index) { this.selectedIndex = -1; }
- },
+ if (that.options.width === 'auto') {
+ styles.width = (that.el.outerWidth() - 2) + 'px';
+ }
- select: function (i) {
- var selectedValue, f;
- selectedValue = this.suggestions[i];
- if (selectedValue) {
- this.el.val(selectedValue);
- if (this.options.autoSubmit) {
- f = this.el.parents('form');
- if (f.length > 0) { f.get(0).submit(); }
- }
- this.ignoreValueChange = true;
- this.hide();
- this.onSelect(i);
- }
- },
+ $(that.suggestionsContainer).css(styles);
+ },
- change: function (i) {
- var selectedValue, fn, me;
- me = this;
- selectedValue = this.suggestions[i];
- if (selectedValue) {
- var s, d;
- s = me.suggestions[i];
- d = me.data[i];
- me.el.val(me.getValue(s));
- }
- else {
- s = '';
- d = -1;
- }
+ enableKillerFn: function () {
+ var that = this;
+ $(document).on('click.autocomplete', that.killerFn);
+ },
- fn = me.options.onChange;
- if ($.isFunction(fn)) { fn(s, d, me.el); }
- },
+ disableKillerFn: function () {
+ var that = this;
+ $(document).off('click.autocomplete', that.killerFn);
+ },
- moveUp: function () {
- if (this.selectedIndex === -1) { return; }
- if (this.selectedIndex === 0) {
- this.container.children().get(0).className = '';
- this.selectedIndex = -1;
- this.el.val(this.currentValue);
- return;
- }
- this.adjustScroll(this.selectedIndex - 1);
- },
+ killSuggestions: function () {
+ var that = this;
+ that.stopKillSuggestions();
+ that.intervalId = window.setInterval(function () {
+ that.hide();
+ that.stopKillSuggestions();
+ }, 50);
+ },
- moveDown: function () {
- if (this.selectedIndex === (this.suggestions.length - 1)) { return; }
- this.adjustScroll(this.selectedIndex + 1);
- },
+ stopKillSuggestions: function () {
+ window.clearInterval(this.intervalId);
+ },
- adjustScroll: function (i) {
- var activeItem, offsetTop, upperBound, lowerBound;
- activeItem = this.activate(i);
- offsetTop = activeItem.offsetTop;
- upperBound = this.container.scrollTop();
- lowerBound = upperBound + this.options.maxHeight - 25;
- if (offsetTop < upperBound) {
- this.container.scrollTop(offsetTop);
- } else if (offsetTop > lowerBound) {
- this.container.scrollTop(offsetTop - this.options.maxHeight + 25);
- }
- this.el.val(this.getValue(this.suggestions[i]));
- },
+ isCursorAtEnd: function () {
+ var that = this,
+ valLength = that.el.val().length,
+ selectionStart = that.element.selectionStart,
+ range;
- onSelect: function (i) {
- var me, fn, s, d;
- me = this;
- fn = me.options.onSelect;
- s = me.suggestions[i];
- d = me.data[i];
- me.el.val(me.getValue(s));
- if ($.isFunction(fn)) { fn(s, d, me.el); }
- },
+ if (typeof selectionStart === 'number') {
+ return selectionStart === valLength;
+ }
+ if (document.selection) {
+ range = document.selection.createRange();
+ range.moveStart('character', -valLength);
+ return valLength === range.text.length;
+ }
+ return true;
+ },
- getValue: function (value) {
- var del, currVal, arr, me;
- me = this;
- del = me.options.delimiter;
- if (!del) { return value; }
- currVal = me.currentValue;
- arr = currVal.split(del);
- if (arr.length === 1) { return value; }
- return currVal.substr(0, currVal.length - arr[arr.length - 1].length) + value;
- }
+ onKeyPress: function (e) {
+ var that = this;
- };
+ // If suggestions are hidden and user presses arrow down, display suggestions:
+ if (!that.disabled && !that.visible && e.which === keys.DOWN && that.currentValue) {
+ that.suggest();
+ return;
+ }
-} (jQuery));
+ if (that.disabled || !that.visible) {
+ return;
+ }
+
+ switch (e.which) {
+ case keys.ESC:
+ that.el.val(that.currentValue);
+ that.hide();
+ break;
+ case keys.RIGHT:
+ if (that.hint && that.options.onHint && that.isCursorAtEnd()) {
+ that.selectHint();
+ break;
+ }
+ return;
+ case keys.TAB:
+ if (that.hint && that.options.onHint) {
+ that.selectHint();
+ return;
+ }
+ // Fall through to RETURN
+ case keys.RETURN:
+ if (that.selectedIndex === -1) {
+ that.hide();
+ return;
+ }
+ that.select(that.selectedIndex);
+ if (e.which === keys.TAB && that.options.tabDisabled === false) {
+ return;
+ }
+ break;
+ case keys.UP:
+ that.moveUp();
+ break;
+ case keys.DOWN:
+ that.moveDown();
+ break;
+ default:
+ return;
+ }
+
+ // Cancel event if function did not return:
+ e.stopImmediatePropagation();
+ e.preventDefault();
+ },
+
+ onKeyUp: function (e) {
+ var that = this;
+
+ if (that.disabled) {
+ return;
+ }
+
+ switch (e.which) {
+ case keys.UP:
+ case keys.DOWN:
+ return;
+ }
+
+ clearInterval(that.onChangeInterval);
+
+ if (that.currentValue !== that.el.val()) {
+ that.findBestHint();
+ if (that.options.deferRequestBy > 0) {
+ // Defer lookup in case when value changes very quickly:
+ that.onChangeInterval = setInterval(function () {
+ that.onValueChange();
+ }, that.options.deferRequestBy);
+ } else {
+ that.onValueChange();
+ }
+ }
+ },
+
+ onValueChange: function () {
+ var that = this,
+ options = that.options,
+ value = that.el.val(),
+ query = that.getQuery(value),
+ index;
+
+ if (that.selection) {
+ that.selection = null;
+ (options.onInvalidateSelection || $.noop).call(that.element);
+ }
+
+ clearInterval(that.onChangeInterval);
+ that.currentValue = value;
+ that.selectedIndex = -1;
+
+ // Check existing suggestion for the match before proceeding:
+ if (options.triggerSelectOnValidInput) {
+ index = that.findSuggestionIndex(query);
+ if (index !== -1) {
+ that.select(index);
+ return;
+ }
+ }
+
+ if (query.length < options.minChars) {
+ that.hide();
+ } else {
+ that.getSuggestions(query);
+ }
+ },
+
+ findSuggestionIndex: function (query) {
+ var that = this,
+ index = -1,
+ queryLowerCase = query.toLowerCase();
+
+ $.each(that.suggestions, function (i, suggestion) {
+ if (suggestion.value.toLowerCase() === queryLowerCase) {
+ index = i;
+ return false;
+ }
+ });
+
+ return index;
+ },
+
+ getQuery: function (value) {
+ var delimiter = this.options.delimiter,
+ parts;
+
+ if (!delimiter) {
+ return value;
+ }
+ parts = value.split(delimiter);
+ return $.trim(parts[parts.length - 1]);
+ },
+
+ getSuggestionsLocal: function (query) {
+ var that = this,
+ options = that.options,
+ queryLowerCase = query.toLowerCase(),
+ filter = options.lookupFilter,
+ limit = parseInt(options.lookupLimit, 10),
+ data;
+
+ data = {
+ suggestions: $.grep(options.lookup, function (suggestion) {
+ return filter(suggestion, query, queryLowerCase);
+ })
+ };
+
+ if (limit && data.suggestions.length > limit) {
+ data.suggestions = data.suggestions.slice(0, limit);
+ }
+
+ return data;
+ },
+
+ getSuggestions: function (q) {
+ var response,
+ that = this,
+ options = that.options,
+ serviceUrl = options.serviceUrl,
+ data,
+ cacheKey;
+
+ options.params[options.paramName] = q;
+ data = options.ignoreParams ? null : options.params;
+
+ if (that.isLocal) {
+ response = that.getSuggestionsLocal(q);
+ } else {
+ if ($.isFunction(serviceUrl)) {
+ serviceUrl = serviceUrl.call(that.element, q);
+ }
+ cacheKey = serviceUrl + '?' + $.param(data || {});
+ response = that.cachedResponse[cacheKey];
+ }
+
+ if (response && $.isArray(response.suggestions)) {
+ that.suggestions = response.suggestions;
+ that.suggest();
+ } else if (!that.isBadQuery(q)) {
+ if (options.onSearchStart.call(that.element, options.params) === false) {
+ return;
+ }
+ if (that.currentRequest) {
+ that.currentRequest.abort();
+ }
+ that.currentRequest = $.ajax({
+ url: serviceUrl,
+ data: data,
+ type: options.type,
+ dataType: options.dataType
+ }).done(function (data) {
+ that.currentRequest = null;
+ that.processResponse(data, q, cacheKey);
+ options.onSearchComplete.call(that.element, q);
+ }).fail(function (jqXHR, textStatus, errorThrown) {
+ options.onSearchError.call(that.element, q, jqXHR, textStatus, errorThrown);
+ });
+ }
+ },
+
+ isBadQuery: function (q) {
+ var badQueries = this.badQueries,
+ i = badQueries.length;
+
+ while (i--) {
+ if (q.indexOf(badQueries[i]) === 0) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ hide: function () {
+ var that = this;
+ that.visible = false;
+ that.selectedIndex = -1;
+ $(that.suggestionsContainer).hide();
+ that.signalHint(null);
+ },
+
+ suggest: function () {
+ if (this.suggestions.length === 0) {
+ this.hide();
+ return;
+ }
+
+ var that = this,
+ options = that.options,
+ formatResult = options.formatResult,
+ value = that.getQuery(that.currentValue),
+ className = that.classes.suggestion,
+ classSelected = that.classes.selected,
+ container = $(that.suggestionsContainer),
+ beforeRender = options.beforeRender,
+ html = '',
+ index,
+ width;
+
+ if (options.triggerSelectOnValidInput) {
+ index = that.findSuggestionIndex(value);
+ if (index !== -1) {
+ that.select(index);
+ return;
+ }
+ }
+
+ // Build suggestions inner HTML:
+ $.each(that.suggestions, function (i, suggestion) {
+ html += '' + formatResult(suggestion, value) + '
';
+ });
+
+ // If width is auto, adjust width before displaying suggestions,
+ // because if instance was created before input had width, it will be zero.
+ // Also it adjusts if input width has changed.
+ // -2px to account for suggestions border.
+ if (options.width === 'auto') {
+ width = that.el.outerWidth() - 2;
+ container.width(width > 0 ? width : 300);
+ }
+
+ container.html(html);
+
+ // Select first value by default:
+ if (options.autoSelectFirst) {
+ that.selectedIndex = 0;
+ container.children().first().addClass(classSelected);
+ }
+
+ if ($.isFunction(beforeRender)) {
+ beforeRender.call(that.element, container);
+ }
+
+ container.show();
+ that.visible = true;
+
+ that.findBestHint();
+ },
+
+ findBestHint: function () {
+ var that = this,
+ value = that.el.val().toLowerCase(),
+ bestMatch = null;
+
+ if (!value) {
+ return;
+ }
+
+ $.each(that.suggestions, function (i, suggestion) {
+ var foundMatch = suggestion.value.toLowerCase().indexOf(value) === 0;
+ if (foundMatch) {
+ bestMatch = suggestion;
+ }
+ return !foundMatch;
+ });
+
+ that.signalHint(bestMatch);
+ },
+
+ signalHint: function (suggestion) {
+ var hintValue = '',
+ that = this;
+ if (suggestion) {
+ hintValue = that.currentValue + suggestion.value.substr(that.currentValue.length);
+ }
+ if (that.hintValue !== hintValue) {
+ that.hintValue = hintValue;
+ that.hint = suggestion;
+ (this.options.onHint || $.noop)(hintValue);
+ }
+ },
+
+ verifySuggestionsFormat: function (suggestions) {
+ // If suggestions is string array, convert them to supported format:
+ if (suggestions.length && typeof suggestions[0] === 'string') {
+ return $.map(suggestions, function (value) {
+ return { value: value, data: null };
+ });
+ }
+
+ return suggestions;
+ },
+
+ processResponse: function (response, originalQuery, cacheKey) {
+ var that = this,
+ options = that.options,
+ result = options.transformResult(response, originalQuery);
+
+ result.suggestions = that.verifySuggestionsFormat(result.suggestions);
+
+ // Cache results if cache is not disabled:
+ if (!options.noCache) {
+ that.cachedResponse[cacheKey] = result;
+ if (result.suggestions.length === 0) {
+ that.badQueries.push(cacheKey);
+ }
+ }
+
+ // Return if originalQuery is not matching current query:
+ if (originalQuery !== that.getQuery(that.currentValue)) {
+ return;
+ }
+
+ that.suggestions = result.suggestions;
+ that.suggest();
+ },
+
+ activate: function (index) {
+ var that = this,
+ activeItem,
+ selected = that.classes.selected,
+ container = $(that.suggestionsContainer),
+ children = container.children();
+
+ container.children('.' + selected).removeClass(selected);
+
+ that.selectedIndex = index;
+
+ if (that.selectedIndex !== -1 && children.length > that.selectedIndex) {
+ activeItem = children.get(that.selectedIndex);
+ $(activeItem).addClass(selected);
+ return activeItem;
+ }
+
+ return null;
+ },
+
+ selectHint: function () {
+ var that = this,
+ i = $.inArray(that.hint, that.suggestions);
+
+ that.select(i);
+ },
+
+ select: function (i) {
+ var that = this;
+ that.hide();
+ that.onSelect(i);
+ },
+
+ moveUp: function () {
+ var that = this;
+
+ if (that.selectedIndex === -1) {
+ return;
+ }
+
+ if (that.selectedIndex === 0) {
+ $(that.suggestionsContainer).children().first().removeClass(that.classes.selected);
+ that.selectedIndex = -1;
+ that.el.val(that.currentValue);
+ that.findBestHint();
+ return;
+ }
+
+ that.adjustScroll(that.selectedIndex - 1);
+ },
+
+ moveDown: function () {
+ var that = this;
+
+ if (that.selectedIndex === (that.suggestions.length - 1)) {
+ return;
+ }
+
+ that.adjustScroll(that.selectedIndex + 1);
+ },
+
+ adjustScroll: function (index) {
+ var that = this,
+ activeItem = that.activate(index),
+ offsetTop,
+ upperBound,
+ lowerBound,
+ heightDelta = 25;
+
+ if (!activeItem) {
+ return;
+ }
+
+ offsetTop = activeItem.offsetTop;
+ upperBound = $(that.suggestionsContainer).scrollTop();
+ lowerBound = upperBound + that.options.maxHeight - heightDelta;
+
+ if (offsetTop < upperBound) {
+ $(that.suggestionsContainer).scrollTop(offsetTop);
+ } else if (offsetTop > lowerBound) {
+ $(that.suggestionsContainer).scrollTop(offsetTop - that.options.maxHeight + heightDelta);
+ }
+
+ that.el.val(that.getValue(that.suggestions[index].value));
+ that.signalHint(null);
+ },
+
+ onSelect: function (index) {
+ var that = this,
+ onSelectCallback = that.options.onSelect,
+ suggestion = that.suggestions[index];
+
+ that.currentValue = that.getValue(suggestion.value);
+ that.el.val(that.currentValue);
+ that.signalHint(null);
+ that.suggestions = [];
+ that.selection = suggestion;
+
+ if ($.isFunction(onSelectCallback)) {
+ onSelectCallback.call(that.element, suggestion);
+ }
+ },
+
+ getValue: function (value) {
+ var that = this,
+ delimiter = that.options.delimiter,
+ currentValue,
+ parts;
+
+ if (!delimiter) {
+ return value;
+ }
+
+ currentValue = that.currentValue;
+ parts = currentValue.split(delimiter);
+
+ if (parts.length === 1) {
+ return value;
+ }
+
+ return currentValue.substr(0, currentValue.length - parts[parts.length - 1].length) + value;
+ },
+
+ dispose: function () {
+ var that = this;
+ that.el.off('.autocomplete').removeData('autocomplete');
+ that.disableKillerFn();
+ $(window).off('resize.autocomplete', that.fixPositionCapture);
+ $(that.suggestionsContainer).remove();
+ }
+ };
+
+ // Create chainable jQuery plugin:
+ $.fn.autocomplete = function (options, args) {
+ var dataKey = 'autocomplete';
+ // If function invoked without argument return
+ // instance of the first matched element:
+ if (arguments.length === 0) {
+ return this.first().data(dataKey);
+ }
+
+ return this.each(function () {
+ var inputElement = $(this),
+ instance = inputElement.data(dataKey);
+
+ if (typeof options === 'string') {
+ if (instance && typeof instance[options] === 'function') {
+ instance[options](args);
+ }
+ } else {
+ // If instance already exists, destroy it:
+ if (instance && instance.dispose) {
+ instance.dispose();
+ }
+ instance = new Autocomplete(this, options);
+ inputElement.data(dataKey, instance);
+ }
+ });
+ };
+}));
\ No newline at end of file
diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js
index 1997c42a8..73d77dc65 100644
--- a/web/app/assets/javascripts/session.js
+++ b/web/app/assets/javascripts/session.js
@@ -170,7 +170,7 @@
context.jamClient.SessionRegisterCallback("JK.HandleBridgeCallback");
context.jamClient.RegisterRecordingCallbacks("JK.HandleRecordingStartResult", "JK.HandleRecordingStopResult", "JK.HandleRecordingStarted", "JK.HandleRecordingStopped", "JK.HandleRecordingAborted");
context.jamClient.SessionSetAlertCallback("JK.AlertCallback");
- context.jamClient.SessionSetConnectionStatusRefreshRate(3000);
+ context.jamClient.SessionSetConnectionStatusRefreshRate(1000);
// If you load this page directly, the loading of the current user
// is happening in parallel. We can't join the session until the
diff --git a/web/app/assets/javascripts/user_dropdown.js b/web/app/assets/javascripts/user_dropdown.js
index 2d7a57384..3a7369a1a 100644
--- a/web/app/assets/javascripts/user_dropdown.js
+++ b/web/app/assets/javascripts/user_dropdown.js
@@ -21,7 +21,15 @@
}
function events() {
- $('.userinfo').hoverIntent(menuHoverIn, menuHoverOut);
+ $('.userinfo').hoverIntent({
+ over: function () {
+ $('ul.shortcuts', this).fadeIn(100);
+ },
+ out: function() {
+ $('ul.shortcuts', this).fadeOut(100);
+ },
+ timeout: 500
+ });
$('.userinfo .invite-friends .menuheader').on('click', function(e) {
$(this).closest('li').css('height', 'auto').find('ul').toggle();
diff --git a/web/app/assets/stylesheets/client/jamkazam.css.scss b/web/app/assets/stylesheets/client/jamkazam.css.scss
index 305eba56f..f4c7d0623 100644
--- a/web/app/assets/stylesheets/client/jamkazam.css.scss
+++ b/web/app/assets/stylesheets/client/jamkazam.css.scss
@@ -235,6 +235,11 @@ input[type="button"] {
_overflow-x:hidden;
}
+.autocomplete-suggestions { border: 1px solid #999; background: #666; overflow: auto; }
+.autocomplete-suggestion { padding: 2px 5px; white-space: nowrap; overflow: hidden; }
+.autocomplete-selected { background: #F0F0F0; }
+.autocomplete-suggestions strong { font-weight: normal; color: #3399FF; }
+
.autocomplete .selected {
background:$ColorScreenBackground;
cursor:pointer;
@@ -345,20 +350,26 @@ input[type="text"], input[type="password"]{
margin-left:35px;
}
-.op50 {
- opacity: .5;
- -ms-filter: "alpha(opacity=50)";
-}
.op70 {
opacity: .7;
-ms-filter: "alpha(opacity=70)";
}
+.op50 {
+ opacity: .5;
+ -ms-filter: "alpha(opacity=50)";
+}
+
.op30 {
opacity: .3;
-ms-filter: "alpha(opacity=30)";
}
+.op10 {
+ opacity: .1;
+ -ms-filter: "alpha(opacity=10)";
+}
+
.nowrap {
display:inline-block;
white-space:nowrap;
diff --git a/web/app/assets/stylesheets/client/screen_common.css.scss b/web/app/assets/stylesheets/client/screen_common.css.scss
index b552e5cfe..24a8a0635 100644
--- a/web/app/assets/stylesheets/client/screen_common.css.scss
+++ b/web/app/assets/stylesheets/client/screen_common.css.scss
@@ -328,6 +328,11 @@ small, .small {font-size:11px;}
-ms-filter: "alpha(opacity=30)";
}
+.op10 {
+ opacity: .1;
+ -ms-filter: "alpha(opacity=10)";
+}
+
.nowrap {
display:inline-block;
white-space:nowrap;
diff --git a/web/app/controllers/api_search_controller.rb b/web/app/controllers/api_search_controller.rb
index ca68d8c1a..81baf7b6c 100644
--- a/web/app/controllers/api_search_controller.rb
+++ b/web/app/controllers/api_search_controller.rb
@@ -15,6 +15,9 @@ class ApiSearchController < ApiController
@search = Search.band_filter(query, current_user)
end
respond_with @search, responder: ApiResponder, :status => 200
+
+ elsif 1 == params[Search::PARAM_SESSION_INVITE].to_i
+ @search = Search.session_invite_search(params[:query], current_user)
else
@search = Search.text_search(params, current_user)
end
diff --git a/web/app/views/api_search/index.rabl b/web/app/views/api_search/index.rabl
index 05009f2e3..8164c4549 100644
--- a/web/app/views/api_search/index.rabl
+++ b/web/app/views/api_search/index.rabl
@@ -2,6 +2,13 @@ object @search
node :search_type do |ss| ss.search_type end
+if @search.session_invite_search?
+ child(:results => :suggestions) {
+ node :value do |uu| uu.name end
+ node :data do |uu| uu.id end
+ }
+end
+
if @search.bands_text_search?
child(:results => :bands) {
attributes :id, :name, :location, :photo_url, :logo_url, :website
diff --git a/web/app/views/clients/_createSession.html.erb b/web/app/views/clients/_createSession.html.erb
index 5ada0d801..0d228335b 100644
--- a/web/app/views/clients/_createSession.html.erb
+++ b/web/app/views/clients/_createSession.html.erb
@@ -49,7 +49,7 @@
Musician Access:
-
+