|  |  |  | (function() { | 
					
						
							|  |  |  |   'use strict'; | 
					
						
							|  |  |  |   window.Whisper = window.Whisper || {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var ContactsTypeahead = Backbone.TypeaheadCollection.extend({ | 
					
						
							|  |  |  |     typeaheadAttributes: [ | 
					
						
							|  |  |  |       'name', | 
					
						
							|  |  |  |       'e164_number', | 
					
						
							|  |  |  |       'national_number', | 
					
						
							|  |  |  |       'international_number', | 
					
						
							|  |  |  |     ], | 
					
						
							|  |  |  |     database: Whisper.Database, | 
					
						
							|  |  |  |     storeName: 'conversations', | 
					
						
							|  |  |  |     model: Whisper.Conversation, | 
					
						
							|  |  |  |     fetchContacts: function() { | 
					
						
							|  |  |  |       return this.fetch({ reset: true, conditions: { type: 'private' } }); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Whisper.ContactPillView = Whisper.View.extend({ | 
					
						
							|  |  |  |     tagName: 'span', | 
					
						
							|  |  |  |     className: 'recipient', | 
					
						
							|  |  |  |     events: { | 
					
						
							|  |  |  |       'click .remove': 'removeModel', | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     templateName: 'contact_pill', | 
					
						
							|  |  |  |     initialize: function() { | 
					
						
							|  |  |  |       var error = this.model.validate(this.model.attributes); | 
					
						
							|  |  |  |       if (error) { | 
					
						
							|  |  |  |         this.$el.addClass('error'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     removeModel: function() { | 
					
						
							|  |  |  |       this.$el.trigger('remove', { modelId: this.model.id }); | 
					
						
							|  |  |  |       this.remove(); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     render_attributes: function() { | 
					
						
							|  |  |  |       return { name: this.model.getTitle() }; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Whisper.RecipientListView = Whisper.ListView.extend({ | 
					
						
							|  |  |  |     itemView: Whisper.ContactPillView, | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Whisper.SuggestionView = Whisper.ConversationListItemView.extend({ | 
					
						
							|  |  |  |     className: 'contact-details contact', | 
					
						
							|  |  |  |     templateName: 'contact_name_and_number', | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Whisper.SuggestionListView = Whisper.ConversationListView.extend({ | 
					
						
							|  |  |  |     itemView: Whisper.SuggestionView, | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Whisper.RecipientsInputView = Whisper.View.extend({ | 
					
						
							|  |  |  |     className: 'recipients-input', | 
					
						
							|  |  |  |     templateName: 'recipients-input', | 
					
						
							|  |  |  |     initialize: function(options) { | 
					
						
							|  |  |  |       if (options) { | 
					
						
							|  |  |  |         this.placeholder = options.placeholder; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       this.render(); | 
					
						
							|  |  |  |       this.$input = this.$('input.search'); | 
					
						
							|  |  |  |       this.$new_contact = this.$('.new-contact'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Collection of recipients selected for the new message
 | 
					
						
							|  |  |  |       this.recipients = new Whisper.ConversationCollection([], { | 
					
						
							|  |  |  |         comparator: false, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // View to display the selected recipients
 | 
					
						
							|  |  |  |       this.recipients_view = new Whisper.RecipientListView({ | 
					
						
							|  |  |  |         collection: this.recipients, | 
					
						
							|  |  |  |         el: this.$('.recipients'), | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Collection of contacts to match user input against
 | 
					
						
							|  |  |  |       this.typeahead = new ContactsTypeahead(); | 
					
						
							|  |  |  |       this.typeahead.fetchContacts(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // View to display the matched contacts from typeahead
 | 
					
						
							|  |  |  |       this.typeahead_view = new Whisper.SuggestionListView({ | 
					
						
							|  |  |  |         collection: new Whisper.ConversationCollection([], { | 
					
						
							|  |  |  |           comparator: function(m) { | 
					
						
							|  |  |  |             return m.getTitle().toLowerCase(); | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |         }), | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       this.$('.contacts').append(this.typeahead_view.el); | 
					
						
							|  |  |  |       this.initNewContact(); | 
					
						
							|  |  |  |       this.listenTo(this.typeahead, 'reset', this.filterContacts); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     render_attributes: function() { | 
					
						
							|  |  |  |       return { placeholder: this.placeholder || 'name or phone number' }; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     events: { | 
					
						
							|  |  |  |       'input input.search': 'filterContacts', | 
					
						
							|  |  |  |       'select .new-contact': 'addNewRecipient', | 
					
						
							|  |  |  |       'select .contacts': 'addRecipient', | 
					
						
							|  |  |  |       'remove .recipient': 'removeRecipient', | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     filterContacts: function(e) { | 
					
						
							|  |  |  |       var query = this.$input.val(); | 
					
						
							|  |  |  |       if (query.length) { | 
					
						
							|  |  |  |         if (this.maybeNumber(query)) { | 
					
						
							|  |  |  |           this.new_contact_view.model.set('id', query); | 
					
						
							|  |  |  |           this.new_contact_view.render().$el.show(); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           this.new_contact_view.$el.hide(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         this.typeahead_view.collection.reset(this.typeahead.typeahead(query)); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         this.resetTypeahead(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     initNewContact: function() { | 
					
						
							|  |  |  |       if (this.new_contact_view) { | 
					
						
							|  |  |  |         this.new_contact_view.undelegateEvents(); | 
					
						
							|  |  |  |         this.new_contact_view.$el.hide(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       // Creates a view to display a new contact
 | 
					
						
							|  |  |  |       this.new_contact_view = new Whisper.ConversationListItemView({ | 
					
						
							|  |  |  |         el: this.$new_contact, | 
					
						
							|  |  |  |         model: ConversationController.create({ | 
					
						
							|  |  |  |           type: 'private', | 
					
						
							|  |  |  |           newContact: true, | 
					
						
							|  |  |  |         }), | 
					
						
							|  |  |  |       }).render(); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     addNewRecipient: function() { | 
					
						
							|  |  |  |       this.recipients.add(this.new_contact_view.model); | 
					
						
							|  |  |  |       this.initNewContact(); | 
					
						
							|  |  |  |       this.resetTypeahead(); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     addRecipient: function(e, conversation) { | 
					
						
							|  |  |  |       this.recipients.add(this.typeahead.remove(conversation.id)); | 
					
						
							|  |  |  |       this.resetTypeahead(); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     removeRecipient: function(e, data) { | 
					
						
							|  |  |  |       var model = this.recipients.remove(data.modelId); | 
					
						
							|  |  |  |       if (!model.get('newContact')) { | 
					
						
							|  |  |  |         this.typeahead.add(model); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       this.filterContacts(); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     reset: function() { | 
					
						
							|  |  |  |       this.delegateEvents(); | 
					
						
							|  |  |  |       this.typeahead_view.delegateEvents(); | 
					
						
							|  |  |  |       this.recipients_view.delegateEvents(); | 
					
						
							|  |  |  |       this.new_contact_view.delegateEvents(); | 
					
						
							|  |  |  |       this.typeahead.add( | 
					
						
							|  |  |  |         this.recipients.filter(function(model) { | 
					
						
							|  |  |  |           return !model.get('newContact'); | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |       this.recipients.reset([]); | 
					
						
							|  |  |  |       this.resetTypeahead(); | 
					
						
							|  |  |  |       this.typeahead.fetchContacts(); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     resetTypeahead: function() { | 
					
						
							|  |  |  |       this.new_contact_view.$el.hide(); | 
					
						
							|  |  |  |       this.$input.val('').focus(); | 
					
						
							|  |  |  |       this.typeahead_view.collection.reset([]); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     maybeNumber: function(number) { | 
					
						
							|  |  |  |       return number.match(/^\+?[0-9]*$/); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | })(); |