Refactor js search views
This commit is contained in:
parent
bf17205c17
commit
f556a5210e
14 changed files with 772 additions and 766 deletions
|
|
@ -181,7 +181,7 @@ app.Router = Backbone.Router.extend({
|
|||
|
||||
app.page = new app.views.Stream({model : app.stream});
|
||||
app.shortcuts = app.shortcuts || new app.views.StreamShortcuts({el: $(document)});
|
||||
if($("#publisher").length !== 0){
|
||||
if($("#publisher").length !== 0) {
|
||||
app.publisher = app.publisher || new app.views.Publisher({collection : app.stream.items});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,196 +1,122 @@
|
|||
//= require ../search_base_view
|
||||
|
||||
/*
|
||||
* This file is based on jQuery.mentionsInput by Kenneth Auchenberg
|
||||
* licensed under MIT License - http://www.opensource.org/licenses/mit-license.php
|
||||
* Website: https://podio.github.io/jquery-mentions-input/
|
||||
*/
|
||||
|
||||
app.views.PublisherMention = app.views.SearchBase.extend({
|
||||
settings: {
|
||||
triggerChar: "@",
|
||||
minChars: 2,
|
||||
templates: {
|
||||
wrapper: _.template("<div class='mentions-input-box'></div>"),
|
||||
mentionsOverlay: _.template("<div class='mentions-box'><div class='mentions'><div></div></div></div>"),
|
||||
mentionItemSyntax: _.template("@{<%= name %> ; <%= handle %>}"),
|
||||
mentionItemHighlight: _.template("<strong><span><%= name %></span></strong>")
|
||||
}
|
||||
triggerChar: "@",
|
||||
invisibleChar: "\u200B", // zero width space
|
||||
mentionRegex: /@([^@\s]+)$/,
|
||||
|
||||
templates: {
|
||||
mentionItemSyntax: _.template("@{<%= name %> ; <%= handle %>}"),
|
||||
mentionItemHighlight: _.template("<strong><span><%= name %></span></strong>")
|
||||
},
|
||||
|
||||
events: {
|
||||
"keydown #status_message_fake_text": "onInputBoxKeyDown",
|
||||
"keypress #status_message_fake_text": "onInputBoxKeyPress",
|
||||
"input #status_message_fake_text": "onInputBoxInput",
|
||||
"click #status_message_fake_text": "onInputBoxClick",
|
||||
"blur #status_message_fake_text": "onInputBoxBlur",
|
||||
"paste #status_message_fake_text": "onInputBoxPaste"
|
||||
},
|
||||
|
||||
/**
|
||||
* Performs setup of the setup of the plugin.
|
||||
*
|
||||
* this.mentionsCollection: used to keep track of the people mentionned in the post
|
||||
* this.inputBuffer: buffer to keep track of the text currently being typed. It is cleared
|
||||
* each time a mention has been processed.
|
||||
* See this#onInputBoxKeyPress
|
||||
* this.currentDataQuery: contains the query for the search engine
|
||||
*
|
||||
* The plugin initilizes two different elements that will contain the text of the post:
|
||||
*
|
||||
* this.elmInputBox: hidden element which keeps track of typed text formatted following
|
||||
* the mentioning syntax given by this.settings.templates#mentionItemSyntax
|
||||
* For instance, if the user writes the text "Hello @user1", the resulting hidden
|
||||
* text will be: "Hello @{user1 ; user1@pod.tld}. This is the text that is submitted
|
||||
* to the pod when the user posts.
|
||||
* this.elmMentionsOverlay: contains the text that will be displayed to the user
|
||||
*
|
||||
* this.mentionChar is a invisible caracter used to mark the name of the mentionned person
|
||||
* during the process. See this#processMention
|
||||
*/
|
||||
initialize: function(){
|
||||
this.mentionsCollection = [];
|
||||
this.inputBuffer = [];
|
||||
this.currentDataQuery = "";
|
||||
this.mentionChar = "\u200B";
|
||||
initialize: function() {
|
||||
this.mentionedPeople = [];
|
||||
|
||||
this.elmInputBox = this.$el.find("#status_message_fake_text");
|
||||
var elmInputWrapper = this.elmInputBox.parent();
|
||||
this.elmInputBox.wrapAll($(this.settings.templates.wrapper()));
|
||||
var elmWrapperBox = elmInputWrapper.find("> div").first();
|
||||
this.elmMentionsOverlay = $(this.settings.templates.mentionsOverlay());
|
||||
this.elmMentionsOverlay.prependTo(elmWrapperBox);
|
||||
// contains the 'fake text' displayed to the user
|
||||
// also has a data-messageText attribute with the original text
|
||||
this.inputBox = this.$("#status_message_fake_text");
|
||||
// contains the mentions displayed to the user
|
||||
this.mentionsBox = this.$(".mentions-box");
|
||||
this.typeaheadInput = this.$(".typeahead-mention-box");
|
||||
this.bindTypeaheadEvents();
|
||||
|
||||
this.bindMentioningEvents();
|
||||
app.views.SearchBase.prototype.initialize.call(this, {typeaheadElement: this.getTypeaheadInput()});
|
||||
|
||||
this.$el.find(".twitter-typeahead").css({position: "absolute", left: "-1px"});
|
||||
this.$el.find(".twitter-typeahead .tt-menu").css("margin-top", 0);
|
||||
app.views.SearchBase.prototype.initialize.call(this, {
|
||||
typeaheadInput: this.typeaheadInput,
|
||||
customSearch: true,
|
||||
autoselect: true
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Attach events to Typeahead.
|
||||
*/
|
||||
bindMentioningEvents: function(){
|
||||
bindTypeaheadEvents: function() {
|
||||
var self = this;
|
||||
// Process mention when the user selects a result.
|
||||
this.getTypeaheadInput().on("typeahead:select", function(evt, datum){
|
||||
self.processMention(datum);
|
||||
self.resetMentionBox();
|
||||
self.addToFilteredResults(datum);
|
||||
});
|
||||
|
||||
// Highlight the first result when the results dropdown opens
|
||||
this.getTypeaheadInput().on("typeahead:render", function(){
|
||||
self.select(self.$(".tt-menu .tt-suggestion").first());
|
||||
});
|
||||
this.typeaheadInput.on("typeahead:select", function(evt, person) { self.onSuggestionSelection(person); });
|
||||
},
|
||||
|
||||
clearBuffer: function(){
|
||||
this.inputBuffer.length = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Cleans the collection of mentionned people. Rejects every item who's name
|
||||
* is not present in the post an falsy values (false, null, "", etc.)
|
||||
*/
|
||||
updateMentionsCollection: function(){
|
||||
var inputText = this.getInputBoxValue();
|
||||
|
||||
this.mentionsCollection = _.reject(this.mentionsCollection, function(mention){
|
||||
return !mention.name || inputText.indexOf(mention.name) === -1;
|
||||
});
|
||||
this.mentionsCollection = _.compact(this.mentionsCollection);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds mention to the mention collection
|
||||
* @param person Mentionned person.
|
||||
* JSON object of form { handle: <diaspora handle>, name: <name>, ... }
|
||||
*/
|
||||
addMention: function(person){
|
||||
if(!person || !person.name || !person.handle){
|
||||
return;
|
||||
}
|
||||
addPersonToMentions: function(person) {
|
||||
if(!(person && person.name && person.handle)) { return; }
|
||||
// This is needed for processing preview
|
||||
/* jshint camelcase: false */
|
||||
person.diaspora_id = person.handle;
|
||||
/* jshint camelcase: true */
|
||||
this.mentionsCollection.push(person);
|
||||
this.mentionedPeople.push(person);
|
||||
this.ignorePersonForSuggestions(person);
|
||||
},
|
||||
|
||||
cleanMentionedPeople: function() {
|
||||
var inputText = this.inputBox.val();
|
||||
this.mentionedPeople = this.mentionedPeople.filter(function(person) {
|
||||
return person.name && inputText.indexOf(person.name) > -1;
|
||||
});
|
||||
this.ignoreDiasporaIds = this.mentionedPeople.map(function(person) { return person.handle; });
|
||||
},
|
||||
|
||||
onSuggestionSelection: function(person) {
|
||||
var messageText = this.inputBox.val();
|
||||
var caretPosition = this.inputBox[0].selectionStart;
|
||||
var triggerCharPosition = messageText.lastIndexOf(this.triggerChar, caretPosition);
|
||||
|
||||
if(triggerCharPosition === -1) { return; }
|
||||
|
||||
this.addPersonToMentions(person);
|
||||
this.closeSuggestions();
|
||||
|
||||
messageText = messageText.substring(0, triggerCharPosition) +
|
||||
this.invisibleChar + person.name + messageText.substring(caretPosition);
|
||||
|
||||
this.inputBox.val(messageText);
|
||||
this.updateMessageTexts();
|
||||
|
||||
this.inputBox.focus();
|
||||
var newCaretPosition = triggerCharPosition + person.name.length + 1;
|
||||
this.inputBox[0].setSelectionRange(newCaretPosition, newCaretPosition);
|
||||
},
|
||||
|
||||
/**
|
||||
* Process the text to add mention to the post. Every @mention in the text
|
||||
* will be replaced by this.mentionChar + mention.name. This temporary text
|
||||
* will then be replaced by final syntax in this#updateValues
|
||||
*
|
||||
* For instance if the user types text "Hello @use" and selects result user1,
|
||||
* The text will be transformed to "Hello \u200Buser1" before calling this#updateValues
|
||||
*
|
||||
* @param mention Mentionned person.
|
||||
* JSON object of form { handle: <diaspora handle>, name: <name>, ... }
|
||||
*/
|
||||
processMention: function(mention){
|
||||
var currentMessage = this.getInputBoxValue();
|
||||
|
||||
var currentCaretPosition = this.getCaretPosition();
|
||||
var startCaretPosition = currentCaretPosition - (this.currentDataQuery.length + 1);
|
||||
|
||||
// Extracts the text before the mention and the text after it.
|
||||
// startEndIndex is the position where to place the caret at the en of the process
|
||||
var start = currentMessage.substr(0, startCaretPosition);
|
||||
var end = currentMessage.substr(currentCaretPosition, currentMessage.length);
|
||||
var startEndIndex = (start + mention.name).length + 1;
|
||||
|
||||
this.addMention(mention);
|
||||
|
||||
// Cleaning before inserting the value, otherwise auto-complete would be triggered with "old" inputbuffer
|
||||
this.clearBuffer();
|
||||
this.currentDataQuery = "";
|
||||
this.resetMentionBox();
|
||||
|
||||
// Autocompletes mention and updates message text
|
||||
var updatedMessageText = start + this.mentionChar + mention.name + end;
|
||||
this.elmInputBox.val(updatedMessageText);
|
||||
this.updateValues();
|
||||
|
||||
// Set correct focus and caret position
|
||||
this.elmInputBox.focus();
|
||||
this.setCaretPosition(startEndIndex);
|
||||
},
|
||||
|
||||
/**
|
||||
* Replaces every combination of this.mentionChar + mention.name by the
|
||||
* Replaces every combination of this.invisibleChar + mention.name by the
|
||||
* correct syntax for both hidden text and visible one.
|
||||
*
|
||||
* For instance, the text "Hello \u200Buser1" will be tranformed to
|
||||
* "Hello @{user1 ; user1@pod.tld}" in the hidden element and
|
||||
* "Hello <strong><span>user1</span></strong>" in the element visible to the user.
|
||||
*/
|
||||
updateValues: function(){
|
||||
var syntaxMessage = this.getInputBoxValue();
|
||||
var mentionText = this.getInputBoxValue();
|
||||
this.clearFilteredResults();
|
||||
updateMessageTexts: function() {
|
||||
var fakeMessageText = this.inputBox.val(),
|
||||
mentionBoxText = fakeMessageText,
|
||||
messageText = fakeMessageText;
|
||||
|
||||
var self = this;
|
||||
this.mentionedPeople.forEach(function(person) {
|
||||
var mentionName = this.invisibleChar + person.name;
|
||||
messageText = messageText.replace(mentionName, this.templates.mentionItemSyntax(person));
|
||||
var textHighlight = this.templates.mentionItemHighlight({name: _.escape(person.name)});
|
||||
mentionBoxText = mentionBoxText.replace(mentionName, textHighlight);
|
||||
}, this);
|
||||
|
||||
_.each(this.mentionsCollection, function(mention){
|
||||
self.addToFilteredResults(mention);
|
||||
this.inputBox.data("messageText", messageText);
|
||||
this.mentionsBox.find(".mentions").html(mentionBoxText);
|
||||
},
|
||||
|
||||
var mentionVal = self.mentionChar + mention.name;
|
||||
updateTypeaheadInput: function() {
|
||||
var messageText = this.inputBox.val();
|
||||
var caretPosition = this.inputBox[0].selectionStart;
|
||||
var result = this.mentionRegex.exec(messageText.substring(0,caretPosition));
|
||||
|
||||
var textSyntax = self.settings.templates.mentionItemSyntax(mention);
|
||||
syntaxMessage = syntaxMessage.replace(mentionVal, textSyntax);
|
||||
if(result === null) {
|
||||
this.closeSuggestions();
|
||||
return;
|
||||
}
|
||||
|
||||
var textHighlight = self.settings.templates.mentionItemHighlight({name: _.escape(mention.name)});
|
||||
mentionText = mentionText.replace(mentionVal, textHighlight);
|
||||
});
|
||||
|
||||
mentionText = mentionText.replace(/\n/g, "<br/>");
|
||||
mentionText = mentionText.replace(/ {2}/g, " ");
|
||||
|
||||
this.elmInputBox.data("messageText", syntaxMessage);
|
||||
this.elmMentionsOverlay.find("div > div").html(mentionText);
|
||||
// result[1] is the string between the last '@' and the current caret position
|
||||
this.typeaheadInput.typeahead("val", result[1]);
|
||||
this.typeaheadInput.typeahead("open");
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -198,99 +124,69 @@ app.views.PublisherMention = app.views.SearchBase.extend({
|
|||
* @param persons List of people to mention in a post;
|
||||
* JSON object of form { handle: <diaspora handle>, name: <name>, ... }
|
||||
*/
|
||||
prefillMention: function(persons){
|
||||
var self = this;
|
||||
_.each(persons, function(person){
|
||||
self.addMention(person);
|
||||
self.addToFilteredResults(person);
|
||||
var text = self.mentionChar + person.name;
|
||||
if(self.elmInputBox.val().length !== 0){
|
||||
text = self.elmInputBox.val() + " " + text;
|
||||
prefillMention: function(persons) {
|
||||
persons.forEach(function(person) {
|
||||
this.addPersonToMentions(person);
|
||||
var text = this.invisibleChar + person.name;
|
||||
if(this.inputBox.val().length !== 0) {
|
||||
text = this.inputBox.val() + " " + text;
|
||||
}
|
||||
self.elmInputBox.val(text);
|
||||
self.updateValues();
|
||||
});
|
||||
this.inputBox.val(text);
|
||||
this.updateMessageTexts();
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Selects next or previous result when result dropdown is open and
|
||||
* user press up and down arrows.
|
||||
*/
|
||||
onArrowKeysPress: function(e){
|
||||
if(!this.isVisible() || (e.which !== Keycodes.UP && e.which !== Keycodes.DOWN)){
|
||||
onArrowKeyDown: function(e) {
|
||||
if(!this.isVisible() || (e.which !== Keycodes.UP && e.which !== Keycodes.DOWN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
this.getTypeaheadInput().typeahead("activate");
|
||||
this.getTypeaheadInput().typeahead("open");
|
||||
this.getTypeaheadInput().trigger($.Event("keydown", {keyCode: e.keyCode, which: e.which}));
|
||||
},
|
||||
|
||||
onInputBoxKeyPress: function(e){
|
||||
// Excluding ctrl+v from key press event in firefox
|
||||
if(!((String.fromCharCode(e.which).toLowerCase() === "v" && e.ctrlKey) || (e.which === Keycodes.BACKSPACE))){
|
||||
var typedValue = String.fromCharCode(e.which || e.keyCode);
|
||||
this.inputBuffer.push(typedValue);
|
||||
}
|
||||
this.typeaheadInput.typeahead("activate");
|
||||
this.typeaheadInput.typeahead("open");
|
||||
this.typeaheadInput.trigger($.Event("keydown", {keyCode: e.keyCode, which: e.which}));
|
||||
},
|
||||
|
||||
/**
|
||||
* Listens for user input and opens results dropdown when input contains the trigger char
|
||||
*/
|
||||
onInputBoxInput: function(){
|
||||
this.updateValues();
|
||||
this.updateMentionsCollection();
|
||||
|
||||
var triggerCharIndex = _.lastIndexOf(this.inputBuffer, this.settings.triggerChar);
|
||||
if(triggerCharIndex > -1){
|
||||
this.currentDataQuery = this.inputBuffer.slice(triggerCharIndex + 1).join("");
|
||||
this.currentDataQuery = this.rtrim(this.currentDataQuery);
|
||||
|
||||
this.showMentionBox();
|
||||
}
|
||||
onInputBoxInput: function() {
|
||||
this.cleanMentionedPeople();
|
||||
this.updateMessageTexts();
|
||||
this.updateTypeaheadInput();
|
||||
},
|
||||
|
||||
onInputBoxKeyDown: function(e){
|
||||
onInputBoxKeyDown: function(e) {
|
||||
// This also matches HOME/END on OSX which is CMD+LEFT, CMD+RIGHT
|
||||
if(e.which === Keycodes.LEFT || e.which === Keycodes.RIGHT ||
|
||||
e.which === Keycodes.HOME || e.which === Keycodes.END){
|
||||
_.defer(this.clearBuffer);
|
||||
|
||||
// IE9 doesn't fire the oninput event when backspace or delete is pressed. This causes the highlighting
|
||||
// to stay on the screen whenever backspace is pressed after a highlighed word. This is simply a hack
|
||||
// to force updateValues() to fire when backspace/delete is pressed in IE9.
|
||||
if(navigator.userAgent.indexOf("MSIE 9") > -1){
|
||||
_.defer(this.updateValues);
|
||||
}
|
||||
|
||||
e.which === Keycodes.HOME || e.which === Keycodes.END) {
|
||||
_.defer(_.bind(this.updateTypeaheadInput, this));
|
||||
return;
|
||||
}
|
||||
|
||||
if(e.which === Keycodes.BACKSPACE){
|
||||
this.inputBuffer = this.inputBuffer.slice(0, this.inputBuffer.length - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.isVisible){
|
||||
if(!this.isVisible) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch(e.which){
|
||||
switch(e.which) {
|
||||
case Keycodes.ESC:
|
||||
case Keycodes.SPACE:
|
||||
this.resetMentionBox();
|
||||
this.closeSuggestions();
|
||||
break;
|
||||
case Keycodes.UP:
|
||||
case Keycodes.DOWN:
|
||||
this.onArrowKeysPress(e);
|
||||
this.onArrowKeyDown(e);
|
||||
break;
|
||||
case Keycodes.RETURN:
|
||||
case Keycodes.TAB:
|
||||
if(this.getSelected().size() === 1){
|
||||
this.getSelected().click();
|
||||
if(this.$(".tt-cursor").length === 1) {
|
||||
this.$(".tt-cursor").click();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -298,69 +194,29 @@ app.views.PublisherMention = app.views.SearchBase.extend({
|
|||
return true;
|
||||
},
|
||||
|
||||
onInputBoxClick: function(){
|
||||
this.resetMentionBox();
|
||||
onInputBoxClick: function() {
|
||||
this.updateTypeaheadInput();
|
||||
},
|
||||
|
||||
onInputBoxBlur: function(){
|
||||
this.resetMentionBox();
|
||||
onInputBoxBlur: function() {
|
||||
this.closeSuggestions();
|
||||
},
|
||||
|
||||
onInputBoxPaste: function(evt){
|
||||
var pastedData = evt.originalEvent.clipboardData.getData("text/plain");
|
||||
var dataArray = pastedData.split("");
|
||||
var self = this;
|
||||
_.each(dataArray, function(value){
|
||||
self.inputBuffer.push(value);
|
||||
});
|
||||
reset: function() {
|
||||
this.inputBox.val("");
|
||||
this.onInputBoxInput();
|
||||
},
|
||||
|
||||
reset: function(){
|
||||
this.elmInputBox.val("");
|
||||
this.mentionsCollection.length = 0;
|
||||
this.clearFilteredResults();
|
||||
this.updateValues();
|
||||
closeSuggestions: function() {
|
||||
this.typeaheadInput.typeahead("val", "");
|
||||
this.typeaheadInput.typeahead("close");
|
||||
},
|
||||
|
||||
showMentionBox: function(){
|
||||
this.getTypeaheadInput().typeahead("val", this.currentDataQuery);
|
||||
this.getTypeaheadInput().typeahead("open");
|
||||
isVisible: function() {
|
||||
return this.$(".tt-menu").is(":visible");
|
||||
},
|
||||
|
||||
resetMentionBox: function(){
|
||||
this.getTypeaheadInput().typeahead("val", "");
|
||||
this.getTypeaheadInput().typeahead("close");
|
||||
},
|
||||
|
||||
getInputBoxValue: function(){
|
||||
return $.trim(this.elmInputBox.val());
|
||||
},
|
||||
|
||||
isVisible: function(){
|
||||
return this.$el.find(".tt-menu").is(":visible");
|
||||
},
|
||||
|
||||
getTypeaheadInput: function(){
|
||||
if(this.$el.find(".typeahead-mention-box").length === 0){
|
||||
this.elmInputBox.after("<input class='typeahead-mention-box hidden' type='text'/>");
|
||||
}
|
||||
return this.$el.find(".typeahead-mention-box");
|
||||
},
|
||||
|
||||
getTextForSubmit: function(){
|
||||
return this.mentionsCollection.length ? this.elmInputBox.data("messageText") : this.getInputBoxValue();
|
||||
},
|
||||
|
||||
setCaretPosition: function(caretPos){
|
||||
this.elmInputBox[0].focus();
|
||||
this.elmInputBox[0].setSelectionRange(caretPos, caretPos);
|
||||
},
|
||||
|
||||
getCaretPosition: function(){
|
||||
return this.elmInputBox[0].selectionStart;
|
||||
},
|
||||
|
||||
rtrim: function(string){
|
||||
return string.replace(/\s+$/, "");
|
||||
getTextForSubmit: function() {
|
||||
return this.mentionedPeople.length ? this.inputBox.data("messageText") : this.inputBox.val();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@
|
|||
* the COPYRIGHT file.
|
||||
*/
|
||||
|
||||
//= require ./publisher/services_view
|
||||
//= require ./publisher/aspect_selector_view
|
||||
//= require ./publisher/getting_started_view
|
||||
//= require ./publisher/mention_view
|
||||
//= require ./publisher/poll_creator_view
|
||||
//= require ./publisher/services_view
|
||||
//= require ./publisher/uploader_view
|
||||
//= require jquery-textchange
|
||||
|
||||
|
|
@ -99,7 +101,7 @@ app.views.Publisher = Backbone.View.extend({
|
|||
|
||||
initSubviews: function() {
|
||||
this.mention = new app.views.PublisherMention({ el: this.$("#publisher_textarea_wrapper") });
|
||||
if(this.prefillMention){
|
||||
if(this.prefillMention) {
|
||||
this.mention.prefillMention([this.prefillMention]);
|
||||
}
|
||||
|
||||
|
|
@ -299,7 +301,7 @@ app.views.Publisher = Backbone.View.extend({
|
|||
|
||||
var serializedForm = $(evt.target).closest("form").serializeObject();
|
||||
var photos = this.getUploadedPhotos();
|
||||
var mentionedPeople = this.mention.mentionsCollection;
|
||||
var mentionedPeople = this.mention.mentionedPeople;
|
||||
var date = (new Date()).toISOString();
|
||||
var poll = this.getPollData(serializedForm);
|
||||
var locationCoords = serializedForm["location[coords]"];
|
||||
|
|
@ -365,6 +367,9 @@ app.views.Publisher = Backbone.View.extend({
|
|||
},
|
||||
|
||||
clear : function() {
|
||||
// remove mentions
|
||||
this.mention.reset();
|
||||
|
||||
// clear text(s)
|
||||
this.inputEl.val("");
|
||||
this.hiddenInputEl.val("");
|
||||
|
|
@ -372,9 +377,6 @@ app.views.Publisher = Backbone.View.extend({
|
|||
.trigger("keydown");
|
||||
autosize.update(this.inputEl);
|
||||
|
||||
// remove mentions
|
||||
this.mention.reset();
|
||||
|
||||
// remove photos
|
||||
this.photozoneEl.find("li").remove();
|
||||
this.$("input[name='photos[]']").remove();
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
app.views.SearchBase = app.views.Base.extend({
|
||||
initialize: function(options){
|
||||
this.typeaheadElement = $(options.typeaheadElement);
|
||||
this.setupBloodhound();
|
||||
initialize: function(options) {
|
||||
this.ignoreDiasporaIds = [];
|
||||
this.typeaheadInput = options.typeaheadInput;
|
||||
this.setupBloodhound(options);
|
||||
if(options.customSearch) { this.setupCustomSearch(); }
|
||||
this.setupTypeahead();
|
||||
this.bindSelectionEvents();
|
||||
this.resultsTofilter = [];
|
||||
// TODO: Remove this as soon as corejavascript/typeahead.js has its first release
|
||||
this.setupMouseSelectionEvents();
|
||||
if(options.autoselect) { this.setupAutoselect(); }
|
||||
},
|
||||
|
||||
setupBloodhound: function() {
|
||||
var self = this;
|
||||
var bloodhoundConf = {
|
||||
setupBloodhound: function(options) {
|
||||
var bloodhoundOptions = {
|
||||
datumTokenizer: function(datum) {
|
||||
var nameTokens = Bloodhound.tokenizers.nonword(datum.name);
|
||||
var handleTokens = datum.handle ? Bloodhound.tokenizers.nonword(datum.name) : [];
|
||||
|
|
@ -24,32 +26,25 @@ app.views.SearchBase = app.views.Base.extend({
|
|||
sufficient: 5
|
||||
};
|
||||
|
||||
// The publisher does not define an additionnal source for searchin
|
||||
// This prevents tests from failing when this additionnal source isn't set
|
||||
if(this.searchFormAction !== undefined){
|
||||
bloodhoundConf.remote = {
|
||||
url: this.searchFormAction + ".json?q=%QUERY",
|
||||
// Allow bloodhound to look for remote results if there is a route given in the options
|
||||
if(options.remoteRoute) {
|
||||
bloodhoundOptions.remote = {
|
||||
url: options.remoteRoute + ".json?q=%QUERY",
|
||||
wildcard: "%QUERY",
|
||||
transform: this.transformBloodhoundResponse
|
||||
};
|
||||
}
|
||||
|
||||
this.bloodhound = new Bloodhound(bloodhoundConf);
|
||||
this.bloodhound = new Bloodhound(bloodhoundOptions);
|
||||
},
|
||||
|
||||
/**
|
||||
* Custom searching function that let us filter contacts from prefetched Bloodhound results.
|
||||
*/
|
||||
this.bloodhound.customSearch = function(query, sync, async){
|
||||
var filterResults = function(datums){
|
||||
return _.filter(datums, function(result){
|
||||
if(result.handle){
|
||||
return !_.contains(self.resultsTofilter, result.handle);
|
||||
}
|
||||
setupCustomSearch: function() {
|
||||
var self = this;
|
||||
this.bloodhound.customSearch = function(query, sync, async) {
|
||||
var _sync = function(datums) {
|
||||
var results = datums.filter(function(datum) {
|
||||
return datum.handle !== undefined && self.ignoreDiasporaIds.indexOf(datum.handle) === -1;
|
||||
});
|
||||
};
|
||||
|
||||
var _sync = function(datums){
|
||||
var results = filterResults(datums);
|
||||
sync(results);
|
||||
};
|
||||
|
||||
|
|
@ -58,7 +53,7 @@ app.views.SearchBase = app.views.Base.extend({
|
|||
},
|
||||
|
||||
setupTypeahead: function() {
|
||||
this.typeaheadElement.typeahead({
|
||||
this.typeaheadInput.typeahead({
|
||||
hint: false,
|
||||
highlight: true,
|
||||
minLength: 2
|
||||
|
|
@ -67,7 +62,7 @@ app.views.SearchBase = app.views.Base.extend({
|
|||
name: "search",
|
||||
display: "name",
|
||||
limit: 5,
|
||||
source: this.searchFormAction !== undefined ? this.bloodhound : this.bloodhound.customSearch,
|
||||
source: this.bloodhound.customSearch !== undefined ? this.bloodhound.customSearch : this.bloodhound,
|
||||
templates: {
|
||||
/* jshint camelcase: false */
|
||||
suggestion: HandlebarsTemplates.search_suggestion_tpl
|
||||
|
|
@ -77,9 +72,9 @@ app.views.SearchBase = app.views.Base.extend({
|
|||
},
|
||||
|
||||
transformBloodhoundResponse: function(response) {
|
||||
return response.map(function(data){
|
||||
return response.map(function(data) {
|
||||
// person
|
||||
if(data.handle){
|
||||
if(data.handle) {
|
||||
data.person = true;
|
||||
return data;
|
||||
}
|
||||
|
|
@ -93,49 +88,37 @@ app.views.SearchBase = app.views.Base.extend({
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* This bind events to highlight a result when overing it
|
||||
*/
|
||||
bindSelectionEvents: function(){
|
||||
var self = this;
|
||||
var onover = function(suggestion){
|
||||
return function(){
|
||||
self.select(suggestion);
|
||||
};
|
||||
};
|
||||
_deselectAllSuggestions: function() {
|
||||
this.$(".tt-suggestion").removeClass("tt-cursor");
|
||||
},
|
||||
|
||||
this.typeaheadElement.on("typeahead:render", function(){
|
||||
self.$(".tt-menu *").off("mouseover");
|
||||
self.$(".tt-menu .tt-suggestion").each(function(){
|
||||
var $suggestion = $(this);
|
||||
$suggestion.on("mouseover", onover($suggestion));
|
||||
$suggestion.find("*").on("mouseover", onover($suggestion));
|
||||
});
|
||||
_selectSuggestion: function(suggestion) {
|
||||
this._deselectAllSuggestions();
|
||||
suggestion.addClass("tt-cursor");
|
||||
},
|
||||
|
||||
// TODO: Remove this as soon as corejavascript/typeahead.js has its first release
|
||||
setupMouseSelectionEvents: function() {
|
||||
var self = this,
|
||||
selectSuggestion = function(e) { self._selectSuggestion($(e.target).closest(".tt-suggestion")); },
|
||||
deselectAllSuggestions = function() { self._deselectAllSuggestions(); };
|
||||
|
||||
this.typeaheadInput.on("typeahead:render", function() {
|
||||
self.$(".tt-menu .tt-suggestion").off("mouseover").on("mouseover", selectSuggestion);
|
||||
self.$(".tt-menu .tt-suggestion *").off("mouseover").on("mouseover", selectSuggestion);
|
||||
self.$(".tt-menu .tt-suggestion").off("mouseleave").on("mouseleave", deselectAllSuggestions);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* This function lets us filter contacts from Bloodhound's responses
|
||||
* It is used by app.views.PublisherMention to filter already mentionned
|
||||
* people in post. Does not filter tags from results.
|
||||
* @param person a JSON object of form { handle: <diaspora handle>, ... } representing the filtered contact
|
||||
*/
|
||||
addToFilteredResults: function(person){
|
||||
if(person.handle){
|
||||
this.resultsTofilter.push(person.handle);
|
||||
}
|
||||
// Selects the first result when the result dropdown opens
|
||||
setupAutoselect: function() {
|
||||
var self = this;
|
||||
this.typeaheadInput.on("typeahead:render", function() {
|
||||
self._selectSuggestion(self.$(".tt-menu .tt-suggestion").first());
|
||||
});
|
||||
},
|
||||
|
||||
clearFilteredResults: function(){
|
||||
this.resultsTofilter.length = 0;
|
||||
ignorePersonForSuggestions: function(person) {
|
||||
if(person.handle) { this.ignoreDiasporaIds.push(person.handle); }
|
||||
},
|
||||
|
||||
getSelected: function(){
|
||||
return this.$el.find(".tt-cursor");
|
||||
},
|
||||
|
||||
select: function(el){
|
||||
this.getSelected().removeClass("tt-cursor");
|
||||
$(el).addClass("tt-cursor");
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,46 +6,29 @@ app.views.Search = app.views.SearchBase.extend({
|
|||
"keypress #q": "inputKeypress"
|
||||
},
|
||||
|
||||
initialize: function(){
|
||||
this.searchFormAction = this.$el.attr("action");
|
||||
app.views.SearchBase.prototype.initialize.call(this, {typeaheadElement: this.getTypeaheadElement()});
|
||||
this.bindMoreSelectionEvents();
|
||||
this.getTypeaheadElement().on("typeahead:select", this.suggestionSelected);
|
||||
},
|
||||
|
||||
/**
|
||||
* This bind events to unselect all results when leaving the menu
|
||||
*/
|
||||
bindMoreSelectionEvents: function(){
|
||||
var self = this;
|
||||
var onleave = function(){
|
||||
self.$(".tt-cursor").removeClass("tt-cursor");
|
||||
};
|
||||
|
||||
this.getTypeaheadElement().on("typeahead:render", function(){
|
||||
self.$(".tt-menu").off("mouseleave", onleave);
|
||||
self.$(".tt-menu").on("mouseleave", onleave);
|
||||
initialize: function() {
|
||||
this.searchInput = this.$("#q");
|
||||
app.views.SearchBase.prototype.initialize.call(this, {
|
||||
typeaheadInput: this.searchInput,
|
||||
remoteRoute: this.$el.attr("action")
|
||||
});
|
||||
this.searchInput.on("typeahead:select", this.suggestionSelected);
|
||||
},
|
||||
|
||||
getTypeaheadElement: function(){
|
||||
return this.$("#q");
|
||||
},
|
||||
|
||||
toggleSearchActive: function(evt){
|
||||
toggleSearchActive: function(evt) {
|
||||
// jQuery produces two events for focus/blur (for bubbling)
|
||||
// don't rely on which event arrives first, by allowing for both variants
|
||||
var isActive = (_.indexOf(["focus","focusin"], evt.type) !== -1);
|
||||
$(evt.target).toggleClass("active", isActive);
|
||||
},
|
||||
|
||||
inputKeypress: function(evt){
|
||||
if(evt.which === Keycodes.ENTER && $(".tt-suggestion.tt-cursor").length === 0){
|
||||
inputKeypress: function(evt) {
|
||||
if(evt.which === Keycodes.ENTER && $(".tt-suggestion.tt-cursor").length === 0) {
|
||||
$(evt.target).closest("form").submit();
|
||||
}
|
||||
},
|
||||
|
||||
suggestionSelected: function(evt, datum){
|
||||
suggestionSelected: function(evt, datum) {
|
||||
window.location = datum.url;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
app.views.Tags = Backbone.View.extend({
|
||||
initialize: function(opts) {
|
||||
if(app.publisher){
|
||||
if(app.publisher) {
|
||||
app.publisher.setText("#"+ opts.hashtagName + " ");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,15 +82,9 @@
|
|||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
|
||||
> div {
|
||||
color: white;
|
||||
white-space: pre-wrap;
|
||||
width: 100%;
|
||||
|
||||
strong {
|
||||
background: #d8dfea;
|
||||
font-weight: normal;
|
||||
}
|
||||
> strong {
|
||||
background: $background-blue;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -252,6 +252,11 @@
|
|||
.hide-location { display: inline-block; }
|
||||
.locator { display: none; }
|
||||
}
|
||||
|
||||
.twitter-typeahead {
|
||||
left: -1px;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.publisher-buttonbar {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
.tt-menu {
|
||||
width: 300px;
|
||||
margin-top: ($navbar-height - $input-height-small) / 2;
|
||||
background-color: $navbar-inverse-bg;
|
||||
box-shadow: 0 5px 10px rgba(0,0,0,.2);
|
||||
}
|
||||
|
||||
.navbar.navbar-fixed-top .tt-menu {
|
||||
margin-top: ($navbar-height - $input-height-small) / 2;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.tt-suggestion {
|
||||
border-top: 1px solid $gray-dark;
|
||||
color: $white;
|
||||
|
|
|
|||
|
|
@ -10,16 +10,20 @@
|
|||
= status.error_messages
|
||||
%params
|
||||
.publisher-textarea-wrapper#publisher_textarea_wrapper
|
||||
- if current_user.getting_started?
|
||||
= status.text_area :fake_text, :rows => 2, :value => h(publisher_formatted_text),
|
||||
:tabindex => 1, :placeholder => "#{t('contacts.index.start_a_conversation')}...",
|
||||
"data-title" => popover_with_close_html("1. " + t("shared.public_explain.share")),
|
||||
"data-content" => t("shared.public_explain.new_user_welcome_message"),
|
||||
"class" => "form-control"
|
||||
- else
|
||||
= status.text_area :fake_text, :rows => 2, :value => h(publisher_formatted_text),
|
||||
:tabindex => 1, :placeholder => "#{t('contacts.index.start_a_conversation')}...",
|
||||
"class" => "form-control"
|
||||
.mentions-input-box
|
||||
.mentions-box
|
||||
.mentions
|
||||
- if current_user.getting_started?
|
||||
= status.text_area :fake_text, :rows => 2, :value => h(publisher_formatted_text),
|
||||
:tabindex => 1, :placeholder => "#{t('contacts.index.start_a_conversation')}...",
|
||||
"data-title" => popover_with_close_html("1. " + t("shared.public_explain.share")),
|
||||
"data-content" => t("shared.public_explain.new_user_welcome_message"),
|
||||
"class" => "form-control"
|
||||
- else
|
||||
= status.text_area :fake_text, :rows => 2, :value => h(publisher_formatted_text),
|
||||
:tabindex => 1, :placeholder => "#{t('contacts.index.start_a_conversation')}...",
|
||||
"class" => "form-control"
|
||||
%input.typeahead-mention-box.hidden{type: "text"}
|
||||
= status.hidden_field :text, value: h(publisher_hidden_text), class: "clear_on_submit"
|
||||
|
||||
.container-fluid#photodropzone_container
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ describe('app.Router', function () {
|
|||
expect(app.publisher.jasmineTestValue).toEqual(42);
|
||||
});
|
||||
|
||||
it("doesn't set app.publisher if there is no publisher element in page", function(){
|
||||
it("doesn't set app.publisher if there is no publisher element in page", function() {
|
||||
$("#publisher").remove();
|
||||
app.router._initializeStreamView();
|
||||
expect(app.publisher).toBeUndefined();
|
||||
|
|
|
|||
|
|
@ -1,322 +1,471 @@
|
|||
describe("app.views.PublisherMention", function(){
|
||||
beforeEach(function(){
|
||||
spec.content().html(
|
||||
"<div id='publisher'>" +
|
||||
"<textarea id='status_message_fake_text'></textarea>" +
|
||||
"</div>");
|
||||
describe("app.views.PublisherMention", function() {
|
||||
beforeEach(function() {
|
||||
spec.loadFixture("aspects_index");
|
||||
});
|
||||
|
||||
describe("initialize", function(){
|
||||
beforeEach(function(){
|
||||
spyOn(app.views.SearchBase.prototype, "initialize").and.callThrough();
|
||||
spyOn(app.views.PublisherMention.prototype, "bindMentioningEvents").and.callThrough();
|
||||
describe("initialize", function() {
|
||||
it("initializes object properties", function() {
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
expect(this.view.mentionedPeople).toEqual([]);
|
||||
expect(this.view.invisibleChar).toBe("\u200B");
|
||||
expect(this.view.triggerChar).toBe("@");
|
||||
});
|
||||
|
||||
it("initializes object properties", function(){
|
||||
expect(this.view.mentionsCollection).toEqual([]);
|
||||
expect(this.view.inputBuffer).toEqual([]);
|
||||
expect(this.view.currentDataQuery).toBe("");
|
||||
expect(this.view.mentionChar).toBe("\u200B");
|
||||
it("calls app.views.SearchBase.initialize", function() {
|
||||
spyOn(app.views.SearchBase.prototype, "initialize");
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
expect(app.views.SearchBase.prototype.initialize).toHaveBeenCalled();
|
||||
var call = app.views.SearchBase.prototype.initialize.calls.mostRecent();
|
||||
expect(call.args[0].typeaheadInput.selector).toBe("#publisher .typeahead-mention-box");
|
||||
expect(call.args[0].customSearch).toBeTruthy();
|
||||
expect(call.args[0].autoselect).toBeTruthy();
|
||||
});
|
||||
|
||||
it("calls completeSetup", function(){
|
||||
expect(app.views.SearchBase.prototype.initialize)
|
||||
.toHaveBeenCalledWith({typeaheadElement: this.view.getTypeaheadInput()});
|
||||
expect(app.views.PublisherMention.prototype.bindMentioningEvents).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("initializes html elements", function(){
|
||||
expect(this.view.$(".typeahead-mention-box").length).toBe(1);
|
||||
expect(this.view.$(".mentions-input-box").length).toBe(1);
|
||||
expect(this.view.$(".mentions-box").length).toBe(1);
|
||||
expect(this.view.$(".mentions").length).toBe(1);
|
||||
it("calls bindTypeaheadEvents", function() {
|
||||
spyOn(app.views.PublisherMention.prototype, "bindTypeaheadEvents");
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
expect(app.views.PublisherMention.prototype.bindTypeaheadEvents).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("bindMentioningEvents", function(){
|
||||
beforeEach(function(){
|
||||
spyOn(app.views.PublisherMention.prototype, "processMention");
|
||||
spyOn(app.views.PublisherMention.prototype, "resetMentionBox");
|
||||
spyOn(app.views.PublisherMention.prototype, "addToFilteredResults");
|
||||
describe("bindTypeaheadEvents", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
this.view.bloodhound.add([
|
||||
{"person": true, "name":"user1", "handle":"user1@pod.tld"},
|
||||
{"person": true, "name":"user2", "handle":"user2@pod.tld"}
|
||||
{person: true, name: "user1", handle: "user1@pod.tld"},
|
||||
{person: true, name: "user2", handle: "user2@pod.tld"}
|
||||
]);
|
||||
});
|
||||
|
||||
it("highlights the first item when rendering results", function(){
|
||||
this.view.getTypeaheadInput().typeahead("val", "user");
|
||||
this.view.getTypeaheadInput().typeahead("open");
|
||||
expect(this.view.$(".tt-suggestion").first()).toHaveClass("tt-cursor");
|
||||
});
|
||||
|
||||
it("process mention when clicking a result", function(){
|
||||
this.view.getTypeaheadInput().typeahead("val", "user");
|
||||
this.view.getTypeaheadInput().typeahead("open");
|
||||
this.view.$(".tt-suggestion").first().click();
|
||||
expect(app.views.PublisherMention.prototype.processMention).toHaveBeenCalled();
|
||||
expect(app.views.PublisherMention.prototype.resetMentionBox).toHaveBeenCalled();
|
||||
expect(app.views.PublisherMention.prototype.addToFilteredResults).toHaveBeenCalled();
|
||||
it("process mention when clicking a result", function() {
|
||||
spyOn(this.view, "onSuggestionSelection");
|
||||
this.view.typeaheadInput.typeahead("val", "user");
|
||||
this.view.typeaheadInput.typeahead("open");
|
||||
$(".tt-suggestion").first().click();
|
||||
expect(this.view.onSuggestionSelection).toHaveBeenCalledWith(
|
||||
{person: true, name: "user1", handle: "user1@pod.tld"}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("updateMentionsCollection", function(){
|
||||
beforeEach(function(){
|
||||
describe("addPersonToMentions", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
});
|
||||
|
||||
it("removes person from mention collection if not mentionned anymore", function(){
|
||||
this.view.mentionsCollection.push({name: "user1"});
|
||||
expect(this.view.mentionsCollection.length).toBe(1);
|
||||
this.view.updateMentionsCollection();
|
||||
expect(this.view.mentionsCollection.length).toBe(0);
|
||||
});
|
||||
|
||||
it("removes item from mention collection if not a person", function(){
|
||||
this.view.mentionsCollection.push({});
|
||||
expect(this.view.mentionsCollection.length).toBe(1);
|
||||
this.view.updateMentionsCollection();
|
||||
expect(this.view.mentionsCollection.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("addMention", function(){
|
||||
beforeEach(function(){
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
});
|
||||
|
||||
it("add person to mentionned people", function(){
|
||||
expect(this.view.mentionsCollection.length).toBe(0);
|
||||
this.view.addMention({"name":"user1", "handle":"user1@pod.tld"});
|
||||
expect(this.view.mentionsCollection.length).toBe(1);
|
||||
expect(this.view.mentionsCollection[0]).toEqual({
|
||||
it("adds a person to mentioned people", function() {
|
||||
expect(this.view.mentionedPeople.length).toBe(0);
|
||||
this.view.addPersonToMentions({name: "user1", handle: "user1@pod.tld"});
|
||||
expect(this.view.mentionedPeople.length).toBe(1);
|
||||
expect(this.view.mentionedPeople[0]).toEqual({
|
||||
/* jshint camelcase: false */
|
||||
"name":"user1", "handle":"user1@pod.tld", diaspora_id: "user1@pod.tld"});
|
||||
name: "user1", handle: "user1@pod.tld", diaspora_id: "user1@pod.tld"});
|
||||
/* jshint camelcase: true */
|
||||
});
|
||||
|
||||
it("does not add mention if not a person", function(){
|
||||
expect(this.view.mentionsCollection.length).toBe(0);
|
||||
this.view.addMention();
|
||||
expect(this.view.mentionsCollection.length).toBe(0);
|
||||
this.view.addMention({});
|
||||
expect(this.view.mentionsCollection.length).toBe(0);
|
||||
this.view.addMention({"name": "user1"});
|
||||
expect(this.view.mentionsCollection.length).toBe(0);
|
||||
this.view.addMention({"handle":"user1@pod.tld"});
|
||||
expect(this.view.mentionsCollection.length).toBe(0);
|
||||
it("adds a person to the ignored diaspora ids", function() {
|
||||
spyOn(this.view, "ignorePersonForSuggestions");
|
||||
this.view.addPersonToMentions({name: "user1", handle: "user1@pod.tld"});
|
||||
expect(this.view.ignorePersonForSuggestions).toHaveBeenCalledWith({
|
||||
/* jshint camelcase: false */
|
||||
name: "user1", handle: "user1@pod.tld", diaspora_id: "user1@pod.tld"});
|
||||
/* jshint camelcase: true */
|
||||
});
|
||||
|
||||
it("doesn't add mention if not a person", function() {
|
||||
expect(this.view.mentionedPeople.length).toBe(0);
|
||||
this.view.addPersonToMentions();
|
||||
expect(this.view.mentionedPeople.length).toBe(0);
|
||||
this.view.addPersonToMentions({});
|
||||
expect(this.view.mentionedPeople.length).toBe(0);
|
||||
this.view.addPersonToMentions({name: "user1"});
|
||||
expect(this.view.mentionedPeople.length).toBe(0);
|
||||
this.view.addPersonToMentions({handle: "user1@pod.tld"});
|
||||
expect(this.view.mentionedPeople.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getTypeaheadInput", function(){
|
||||
beforeEach(function(){
|
||||
describe("cleanMentionedPeople", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
});
|
||||
|
||||
it("inserts typeahead input if it does not already exist", function(){
|
||||
this.view.getTypeaheadInput().remove();
|
||||
expect(this.view.$(".typeahead-mention-box").length).toBe(0);
|
||||
this.view.getTypeaheadInput();
|
||||
expect(this.view.$(".typeahead-mention-box").length).toBe(1);
|
||||
it("removes person from mentioned people if not mentioned anymore", function() {
|
||||
this.view.addPersonToMentions({name: "user1", handle: "user1@pod.tld"});
|
||||
expect(this.view.mentionedPeople.length).toBe(1);
|
||||
this.view.cleanMentionedPeople();
|
||||
expect(this.view.mentionedPeople.length).toBe(0);
|
||||
});
|
||||
|
||||
it("removes person from ignored people if not mentioned anymore", function() {
|
||||
this.view.addPersonToMentions({name: "user1", handle: "user1@pod.tld"});
|
||||
expect(this.view.ignoreDiasporaIds.length).toBe(1);
|
||||
this.view.cleanMentionedPeople();
|
||||
expect(this.view.ignoreDiasporaIds.length).toBe(0);
|
||||
});
|
||||
|
||||
it("keeps mentioned persons", function() {
|
||||
this.view.addPersonToMentions({name: "user1", handle: "user1@pod.tld"});
|
||||
this.view.inputBox.val("user1");
|
||||
expect(this.view.mentionedPeople.length).toBe(1);
|
||||
this.view.cleanMentionedPeople();
|
||||
expect(this.view.mentionedPeople.length).toBe(1);
|
||||
});
|
||||
|
||||
it("keeps mentioned persons for ignored diaspora ids", function() {
|
||||
this.view.addPersonToMentions({name: "user1", handle: "user1@pod.tld"});
|
||||
this.view.inputBox.val("user1");
|
||||
expect(this.view.ignoreDiasporaIds.length).toBe(1);
|
||||
this.view.cleanMentionedPeople();
|
||||
expect(this.view.ignoreDiasporaIds.length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("processMention", function(){
|
||||
beforeEach(function(){
|
||||
describe("onSuggestionSelection", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
this.view.elmInputBox.val("@user1 Text before @user1 text after");
|
||||
this.view.currentDataQuery = "user1";
|
||||
this.view.elmInputBox[0].setSelectionRange(25, 25);
|
||||
this.view.inputBox.val("@user1337 Text before @user1 text after");
|
||||
this.view.inputBox[0].setSelectionRange(28, 28);
|
||||
});
|
||||
|
||||
it("add person to mentionned people", function(){
|
||||
spyOn(this.view, "addMention");
|
||||
this.view.processMention({"name":"user1", "handle":"user1@pod.tld"});
|
||||
expect(this.view.addMention).toHaveBeenCalledWith({"name":"user1", "handle":"user1@pod.tld"});
|
||||
it("doesn't do anything if there is no '@' in front of the caret", function() {
|
||||
spyOn(this.view, "addPersonToMentions");
|
||||
this.view.inputBox.val("user1337 Text before @user1 text after");
|
||||
this.view.inputBox[0].setSelectionRange(9, 9);
|
||||
this.view.onSuggestionSelection({name: "user1337", handle: "user1@pod.tld"});
|
||||
expect(this.view.addPersonToMentions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("cleans buffers", function(){
|
||||
spyOn(this.view, "clearBuffer");
|
||||
spyOn(this.view, "resetMentionBox");
|
||||
this.view.processMention({"name":"user1", "handle":"user1@pod.tld"});
|
||||
expect(this.view.clearBuffer).toHaveBeenCalled();
|
||||
expect(this.view.resetMentionBox).toHaveBeenCalled();
|
||||
expect(this.view.currentDataQuery).toBe("");
|
||||
it("adds a person to mentioned people", function() {
|
||||
spyOn(this.view, "addPersonToMentions");
|
||||
this.view.onSuggestionSelection({name: "user1337", handle: "user1@pod.tld"});
|
||||
expect(this.view.addPersonToMentions).toHaveBeenCalledWith({name: "user1337", handle: "user1@pod.tld"});
|
||||
});
|
||||
|
||||
it("correctly formats the text", function(){
|
||||
spyOn(this.view, "updateValues");
|
||||
this.view.processMention({"name":"user1", "handle":"user1@pod.tld"});
|
||||
expect(this.view.updateValues).toHaveBeenCalled();
|
||||
expect(this.view.getInputBoxValue()).toBe("@user1 Text before " + this.view.mentionChar + "user1 text after");
|
||||
it("closes the suggestions box", function() {
|
||||
spyOn(this.view, "closeSuggestions");
|
||||
this.view.onSuggestionSelection({name: "user1337", handle: "user1@pod.tld"});
|
||||
expect(this.view.closeSuggestions).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("places the caret at the right position", function(){
|
||||
this.view.processMention({"name":"user1WithLongName", "handle":"user1@pod.tld"});
|
||||
var expectedCaretPosition = ("@user1 Text before " + this.view.mentionChar + "user1WithLongName").length;
|
||||
expect(this.view.elmInputBox[0].selectionStart).toBe(expectedCaretPosition);
|
||||
it("correctly formats the text", function() {
|
||||
this.view.onSuggestionSelection({name: "user1337", handle: "user1@pod.tld"});
|
||||
expect(this.view.inputBox.val()).toBe("@user1337 Text before \u200Buser1337 text after");
|
||||
});
|
||||
|
||||
it("replaces the correct mention", function() {
|
||||
this.view.inputBox.val("@user1337 123 user2 @user2 456 @user3 789");
|
||||
this.view.inputBox[0].setSelectionRange(26, 26);
|
||||
this.view.onSuggestionSelection({name: "user23", handle: "user2@pod.tld"});
|
||||
expect(this.view.inputBox.val()).toBe("@user1337 123 user2 \u200Buser23 456 @user3 789");
|
||||
this.view.inputBox[0].setSelectionRange(9, 9);
|
||||
this.view.onSuggestionSelection({name: "user1337", handle: "user1@pod.tld"});
|
||||
expect(this.view.inputBox.val()).toBe("\u200Buser1337 123 user2 \u200Buser23 456 @user3 789");
|
||||
this.view.inputBox[0].setSelectionRange(38, 38);
|
||||
this.view.onSuggestionSelection({name: "user32", handle: "user3@pod.tld"});
|
||||
expect(this.view.inputBox.val()).toBe("\u200Buser1337 123 user2 \u200Buser23 456 \u200Buser32 789");
|
||||
});
|
||||
|
||||
it("calls updateMessageTexts", function() {
|
||||
spyOn(this.view, "updateMessageTexts");
|
||||
this.view.onSuggestionSelection({name: "user1337", handle: "user1@pod.tld"});
|
||||
expect(this.view.updateMessageTexts).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("places the caret at the right position", function() {
|
||||
this.view.onSuggestionSelection({"name": "user1WithLongName", "handle": "user1@pod.tld"});
|
||||
var expectedCaretPosition = ("@user1337 Text before \u200Buser1WithLongName").length;
|
||||
expect(this.view.inputBox[0].selectionStart).toBe(expectedCaretPosition);
|
||||
});
|
||||
});
|
||||
|
||||
describe("updateValues", function(){
|
||||
beforeEach(function(){
|
||||
describe("updateMessageTexts", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
this.view.elmInputBox.val("@user1 Text before " + this.view.mentionChar + "user1\ntext after");
|
||||
this.view.mentionsCollection.push({"name":"user1", "handle":"user1@pod.tld"});
|
||||
this.view.inputBox.val("@user1 Text before \u200Buser1\ntext after");
|
||||
this.view.mentionedPeople.push({"name": "user1", "handle": "user1@pod.tld"});
|
||||
});
|
||||
|
||||
it("filters mention from future results", function(){
|
||||
spyOn(this.view, "clearFilteredResults");
|
||||
spyOn(this.view, "addToFilteredResults");
|
||||
this.view.updateValues();
|
||||
expect(this.view.clearFilteredResults).toHaveBeenCalled();
|
||||
expect(this.view.addToFilteredResults).toHaveBeenCalledWith({"name":"user1", "handle":"user1@pod.tld"});
|
||||
it("sets the correct messageText", function() {
|
||||
this.view.updateMessageTexts();
|
||||
expect(this.view.inputBox.data("messageText")).toBe("@user1 Text before @{user1 ; user1@pod.tld}\ntext after");
|
||||
});
|
||||
|
||||
it("formats message text data with correct mentionning syntax", function(){
|
||||
this.view.updateValues();
|
||||
expect(this.view.elmInputBox.data("messageText")).toBe("@user1 Text before @{user1 ; user1@pod.tld}\ntext after");
|
||||
});
|
||||
|
||||
it("formats overlay text to HTML", function(){
|
||||
this.view.updateValues();
|
||||
expect(this.view.elmMentionsOverlay.find("div > div").html())
|
||||
.toBe("@user1 Text before <strong><span>user1</span></strong><br>text after");
|
||||
it("formats overlay text to HTML", function() {
|
||||
this.view.updateMessageTexts();
|
||||
expect(this.view.mentionsBox.find(".mentions").html())
|
||||
.toBe("@user1 Text before <strong><span>user1</span></strong>\ntext after");
|
||||
});
|
||||
});
|
||||
|
||||
describe("prefillMention", function(){
|
||||
beforeEach(function(){
|
||||
describe("updateTypeaheadInput", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
spyOn(this.view, "addMention");
|
||||
spyOn(this.view, "addToFilteredResults");
|
||||
spyOn(this.view, "updateValues");
|
||||
this.view.inputBox.val("@user1337 Text before @user1 text after");
|
||||
this.view.inputBox[0].setSelectionRange(28, 28);
|
||||
});
|
||||
|
||||
it("prefills one mention", function(){
|
||||
this.view.prefillMention([{"name":"user1", "handle":"user1@pod.tld"}]);
|
||||
|
||||
expect(this.view.addMention).toHaveBeenCalledWith({"name":"user1", "handle":"user1@pod.tld"});
|
||||
expect(this.view.addToFilteredResults)
|
||||
.toHaveBeenCalledWith({"name":"user1", "handle":"user1@pod.tld"});
|
||||
expect(this.view.updateValues).toHaveBeenCalled();
|
||||
expect(this.view.getInputBoxValue()).toBe(this.view.mentionChar + "user1");
|
||||
it("calls 'closeSuggestions' if there is no '@' in front of the caret", function() {
|
||||
spyOn(this.view, "closeSuggestions");
|
||||
this.view.inputBox.val("user1337 Text before @user1 text after");
|
||||
this.view.inputBox[0].setSelectionRange(9, 9);
|
||||
this.view.updateTypeaheadInput();
|
||||
expect(this.view.closeSuggestions).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("prefills multiple mentions", function(){
|
||||
it("calls 'closeSuggestions' if there is a whitespace between the '@' and the caret", function() {
|
||||
spyOn(this.view, "closeSuggestions");
|
||||
this.view.inputBox.val("@user1337 Text before @user1 text after");
|
||||
this.view.inputBox[0].setSelectionRange(9, 9);
|
||||
this.view.updateTypeaheadInput();
|
||||
expect(this.view.closeSuggestions.calls.count()).toEqual(0);
|
||||
this.view.inputBox[0].setSelectionRange(10, 10);
|
||||
this.view.updateTypeaheadInput();
|
||||
expect(this.view.closeSuggestions.calls.count()).toEqual(1);
|
||||
this.view.inputBox[0].setSelectionRange(11, 11);
|
||||
this.view.updateTypeaheadInput();
|
||||
expect(this.view.closeSuggestions.calls.count()).toEqual(2);
|
||||
});
|
||||
|
||||
it("fills the typeahead input with the correct text", function() {
|
||||
spyOn(this.view, "closeSuggestions");
|
||||
this.view.inputBox.val("@user1337 Text before @user1 text after");
|
||||
this.view.inputBox[0].setSelectionRange(2, 2);
|
||||
this.view.updateTypeaheadInput();
|
||||
expect(this.view.closeSuggestions).not.toHaveBeenCalled();
|
||||
expect(this.view.typeaheadInput.val()).toBe("u");
|
||||
this.view.inputBox[0].setSelectionRange(9, 9);
|
||||
this.view.updateTypeaheadInput();
|
||||
expect(this.view.closeSuggestions).not.toHaveBeenCalled();
|
||||
expect(this.view.typeaheadInput.val()).toBe("user1337");
|
||||
this.view.inputBox[0].setSelectionRange(27, 27);
|
||||
this.view.updateTypeaheadInput();
|
||||
expect(this.view.closeSuggestions).not.toHaveBeenCalled();
|
||||
expect(this.view.typeaheadInput.val()).toBe("user");
|
||||
});
|
||||
});
|
||||
|
||||
describe("prefillMention", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
spyOn(this.view, "addPersonToMentions");
|
||||
spyOn(this.view, "updateMessageTexts");
|
||||
});
|
||||
|
||||
it("prefills one mention", function() {
|
||||
this.view.prefillMention([{"name": "user1", "handle": "user1@pod.tld"}]);
|
||||
expect(this.view.addPersonToMentions).toHaveBeenCalledWith({"name": "user1", "handle": "user1@pod.tld"});
|
||||
expect(this.view.updateMessageTexts).toHaveBeenCalled();
|
||||
expect(this.view.inputBox.val()).toBe("\u200Buser1");
|
||||
});
|
||||
|
||||
it("prefills multiple mentions", function() {
|
||||
this.view.prefillMention([
|
||||
{"name":"user1", "handle":"user1@pod.tld"},
|
||||
{"name":"user2", "handle":"user2@pod.tld"}
|
||||
{"name": "user1", "handle": "user1@pod.tld"},
|
||||
{"name": "user2", "handle": "user2@pod.tld"}
|
||||
]);
|
||||
|
||||
expect(this.view.addMention).toHaveBeenCalledWith({"name":"user1", "handle":"user1@pod.tld"});
|
||||
expect(this.view.addMention).toHaveBeenCalledWith({"name":"user2", "handle":"user2@pod.tld"});
|
||||
expect(this.view.addToFilteredResults).toHaveBeenCalledWith({"name":"user1", "handle":"user1@pod.tld"});
|
||||
expect(this.view.addToFilteredResults).toHaveBeenCalledWith({"name":"user2", "handle":"user2@pod.tld"});
|
||||
expect(this.view.updateValues).toHaveBeenCalled();
|
||||
expect(this.view.getInputBoxValue()).toBe(this.view.mentionChar + "user1 " + this.view.mentionChar + "user2");
|
||||
expect(this.view.addPersonToMentions).toHaveBeenCalledWith({"name": "user1", "handle": "user1@pod.tld"});
|
||||
expect(this.view.addPersonToMentions).toHaveBeenCalledWith({"name": "user2", "handle": "user2@pod.tld"});
|
||||
expect(this.view.updateMessageTexts).toHaveBeenCalled();
|
||||
expect(this.view.inputBox.val()).toBe("\u200Buser1 \u200Buser2");
|
||||
});
|
||||
});
|
||||
|
||||
describe("onInputBoxPaste", function(){
|
||||
beforeEach(function(){
|
||||
describe("onInputBoxKeyDown", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
});
|
||||
|
||||
it("add person to mentionned people", function(){
|
||||
var pasteEvent = {originalEvent: {clipboardData: {getData: function(){
|
||||
return "Pasted text";
|
||||
}}}};
|
||||
context("escape key", function() {
|
||||
beforeEach(function() {
|
||||
this.evt = $.Event("keydown", {which: Keycodes.ESC});
|
||||
});
|
||||
|
||||
this.view.onInputBoxPaste(pasteEvent);
|
||||
expect(this.view.inputBuffer).toEqual(["P", "a", "s", "t", "e", "d", " ", "t", "e", "x", "t"]);
|
||||
it("calls 'closeSuggestions'", function() {
|
||||
spyOn(this.view, "closeSuggestions");
|
||||
this.view.onInputBoxKeyDown(this.evt);
|
||||
expect(this.view.closeSuggestions).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
context("space key", function() {
|
||||
beforeEach(function() {
|
||||
this.evt = $.Event("keydown", {which: Keycodes.SPACE});
|
||||
});
|
||||
|
||||
it("calls 'closeSuggestions'", function() {
|
||||
spyOn(this.view, "closeSuggestions");
|
||||
this.view.onInputBoxKeyDown(this.evt);
|
||||
expect(this.view.closeSuggestions).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
context("up key", function() {
|
||||
beforeEach(function() {
|
||||
this.evt = $.Event("keydown", {which: Keycodes.UP});
|
||||
});
|
||||
|
||||
it("calls 'onArrowKeyDown'", function() {
|
||||
spyOn(this.view, "onArrowKeyDown");
|
||||
this.view.onInputBoxKeyDown(this.evt);
|
||||
expect(this.view.onArrowKeyDown).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
context("down key", function() {
|
||||
beforeEach(function() {
|
||||
this.evt = $.Event("keydown", {which: Keycodes.DOWN});
|
||||
});
|
||||
|
||||
it("calls 'onArrowKeyDown'", function() {
|
||||
spyOn(this.view, "onArrowKeyDown");
|
||||
this.view.onInputBoxKeyDown(this.evt);
|
||||
expect(this.view.onArrowKeyDown).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
context("return key", function() {
|
||||
beforeEach(function() {
|
||||
this.evt = $.Event("keydown", {which: Keycodes.RETURN});
|
||||
this.view.bloodhound.add([
|
||||
{person: true, name: "user1", handle: "user1@pod.tld"},
|
||||
{person: true, name: "user2", handle: "user2@pod.tld"}
|
||||
]);
|
||||
this.view.typeaheadInput.typeahead("val", "user");
|
||||
this.view.typeaheadInput.typeahead("open");
|
||||
$(".tt-suggestion").first().addClass(".tt-cursor");
|
||||
});
|
||||
|
||||
it("calls 'onSuggestionSelection'", function() {
|
||||
spyOn(this.view, "onSuggestionSelection");
|
||||
this.view.onInputBoxKeyDown(this.evt);
|
||||
expect(this.view.onSuggestionSelection).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
context("tab key", function() {
|
||||
beforeEach(function() {
|
||||
this.evt = $.Event("keydown", {which: Keycodes.TAB});
|
||||
this.view.bloodhound.add([
|
||||
{person: true, name: "user1", handle: "user1@pod.tld"},
|
||||
{person: true, name: "user2", handle: "user2@pod.tld"}
|
||||
]);
|
||||
this.view.typeaheadInput.typeahead("val", "user");
|
||||
this.view.typeaheadInput.typeahead("open");
|
||||
$(".tt-suggestion").first().addClass(".tt-cursor");
|
||||
});
|
||||
|
||||
it("calls 'onSuggestionSelection'", function() {
|
||||
spyOn(this.view, "onSuggestionSelection");
|
||||
this.view.onInputBoxKeyDown(this.evt);
|
||||
expect(this.view.onSuggestionSelection).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("reset", function(){
|
||||
beforeEach(function(){
|
||||
describe("onInputBoxInput", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
spyOn(this.view, "clearFilteredResults");
|
||||
spyOn(this.view, "updateValues");
|
||||
});
|
||||
|
||||
it("resets the mention box", function(){
|
||||
it("calls 'cleanMentionedPeople'", function() {
|
||||
spyOn(this.view, "cleanMentionedPeople");
|
||||
this.view.onInputBoxInput();
|
||||
expect(this.view.cleanMentionedPeople).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls 'updateMessageTexts'", function() {
|
||||
spyOn(this.view, "updateMessageTexts");
|
||||
this.view.onInputBoxInput();
|
||||
expect(this.view.updateMessageTexts).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls 'updateTypeaheadInput'", function() {
|
||||
spyOn(this.view, "updateTypeaheadInput");
|
||||
this.view.onInputBoxInput();
|
||||
expect(this.view.updateTypeaheadInput).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("onInputBoxClick", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
});
|
||||
|
||||
it("calls 'updateTypeaheadInput'", function() {
|
||||
spyOn(this.view, "updateTypeaheadInput");
|
||||
this.view.onInputBoxClick();
|
||||
expect(this.view.updateTypeaheadInput).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("onInputBoxBlur", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
});
|
||||
|
||||
it("calls 'closeSuggestions'", function() {
|
||||
spyOn(this.view, "closeSuggestions");
|
||||
this.view.onInputBoxBlur();
|
||||
expect(this.view.closeSuggestions).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("reset", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
spyOn(this.view, "onInputBoxInput");
|
||||
});
|
||||
|
||||
it("resets the mention box", function() {
|
||||
this.view.reset();
|
||||
expect(this.view.elmInputBox.val()).toBe("");
|
||||
expect(this.view.mentionsCollection.length).toBe(0);
|
||||
expect(this.view.clearFilteredResults).toHaveBeenCalled();
|
||||
expect(this.view.updateValues).toHaveBeenCalled();
|
||||
expect(this.view.inputBox.val()).toBe("");
|
||||
expect(this.view.onInputBoxInput).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("showMentionBox", function(){
|
||||
beforeEach(function(){
|
||||
describe("closeSuggestions", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
this.view.bloodhound.add([
|
||||
{"person": true, "name":"user1", "handle":"user1@pod.tld"}
|
||||
{"person": true, "name": "user1", "handle": "user1@pod.tld"}
|
||||
]);
|
||||
this.view.currentDataQuery = "user1";
|
||||
});
|
||||
|
||||
it("shows the mention box", function(){
|
||||
it("resets results and closes mention box", function() {
|
||||
this.view.typeaheadInput.typeahead("val", "user");
|
||||
this.view.typeaheadInput.typeahead("open");
|
||||
expect(this.view.$(".tt-menu").is(":visible")).toBe(true);
|
||||
expect(this.view.$(".tt-menu .tt-suggestion").length).toBeGreaterThan(0);
|
||||
expect(this.view.typeaheadInput.val()).toBe("user");
|
||||
this.view.closeSuggestions();
|
||||
expect(this.view.$(".tt-menu").is(":visible")).toBe(false);
|
||||
expect(this.view.$(".tt-menu .tt-suggestion").length).toBe(0);
|
||||
this.view.showMentionBox();
|
||||
expect(this.view.$(".tt-menu").is(":visible")).toBe(true);
|
||||
expect(this.view.$(".tt-menu .tt-suggestion").length).toBe(1);
|
||||
expect(this.view.typeaheadInput.val()).toBe("");
|
||||
});
|
||||
});
|
||||
|
||||
describe("resetMentionBox", function(){
|
||||
beforeEach(function(){
|
||||
describe("getTextForSubmit", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
this.view.bloodhound.add([
|
||||
{"person": true, "name":"user1", "handle":"user1@pod.tld"}
|
||||
{person: true, name: "user1", handle: "user1@pod.tld"}
|
||||
]);
|
||||
});
|
||||
|
||||
it("resets results and closes mention box", function(){
|
||||
this.view.getTypeaheadInput().typeahead("val", "user");
|
||||
this.view.getTypeaheadInput().typeahead("open");
|
||||
expect(this.view.$(".tt-menu").is(":visible")).toBe(true);
|
||||
expect(this.view.$(".tt-menu .tt-suggestion").length >= 1).toBe(true);
|
||||
this.view.resetMentionBox();
|
||||
expect(this.view.$(".tt-menu").is(":visible")).toBe(false);
|
||||
expect(this.view.$(".tt-menu .tt-suggestion").length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getInputBoxValue", function(){
|
||||
beforeEach(function(){
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
});
|
||||
|
||||
it("returns trimmed text", function(){
|
||||
this.view.elmInputBox.val("Text with trailing spaces ");
|
||||
expect(this.view.getInputBoxValue()).toBe("Text with trailing spaces");
|
||||
});
|
||||
});
|
||||
|
||||
describe("getTextForSubmit", function(){
|
||||
beforeEach(function(){
|
||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||
this.view.bloodhound.add([
|
||||
{"person": true, "name":"user1", "handle":"user1@pod.tld"}
|
||||
]);
|
||||
});
|
||||
|
||||
it("returns text with mention syntax if someone is mentionned", function(){
|
||||
this.view.getTypeaheadInput().typeahead("val", "user");
|
||||
this.view.getTypeaheadInput().typeahead("open");
|
||||
it("returns text with mention if someone has been mentioned", function() {
|
||||
this.view.inputBox.val("@user");
|
||||
this.view.inputBox[0].setSelectionRange(5, 5);
|
||||
this.view.typeaheadInput.typeahead("val", "user");
|
||||
this.view.typeaheadInput.typeahead("open");
|
||||
this.view.$(".tt-suggestion").first().click();
|
||||
expect(this.view.getTextForSubmit()).toBe("@{user1 ; user1@pod.tld}");
|
||||
});
|
||||
|
||||
it("returns normal text if nobody is mentionned", function(){
|
||||
this.view.elmInputBox.data("messageText", "Bad text");
|
||||
this.view.elmInputBox.val("Good text");
|
||||
it("returns normal text if nobody has been mentioned", function() {
|
||||
this.view.inputBox.data("messageText", "Bad text");
|
||||
this.view.inputBox.val("Good text");
|
||||
expect(this.view.getTextForSubmit()).toBe("Good text");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,75 +1,106 @@
|
|||
describe("app.views.SearchBase", function() {
|
||||
beforeEach(function(){
|
||||
beforeEach(function() {
|
||||
spec.content().html(
|
||||
"<form action='/search' id='search_people_form'><input id='q' name='q' type='search'/></form>"
|
||||
);
|
||||
this.search = function(view, name) {
|
||||
view.$("#q").trigger("focusin");
|
||||
view.$("#q").val(name);
|
||||
view.$("#q").trigger("keypress");
|
||||
view.$("#q").trigger("input");
|
||||
view.$("#q").trigger("focus");
|
||||
};
|
||||
this.bloodhoundData = [
|
||||
{"person": true, "name": "user1", "handle": "user1@pod.tld"},
|
||||
{"person": true, "name": "user2", "handle": "user2@pod.tld"}
|
||||
];
|
||||
});
|
||||
|
||||
describe("initialize", function(){
|
||||
it("calls setupBloodhound", function(){
|
||||
describe("initialize", function() {
|
||||
it("calls setupBloodhound", function() {
|
||||
spyOn(app.views.SearchBase.prototype, "setupBloodhound").and.callThrough();
|
||||
new app.views.SearchBase({el: "#search_people_form"});
|
||||
this.view = new app.views.SearchBase({el: "#search_people_form", typeaheadInput: $("#q")});
|
||||
expect(app.views.SearchBase.prototype.setupBloodhound).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls setupTypeahead", function(){
|
||||
it("doesn't call setupCustomSearch if customSearch hasn't been enabled", function() {
|
||||
spyOn(app.views.SearchBase.prototype, "setupCustomSearch");
|
||||
this.view = new app.views.SearchBase({el: "#search_people_form", typeaheadInput: $("#q")});
|
||||
expect(app.views.SearchBase.prototype.setupCustomSearch).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls setupCustomSearch if customSearch has been enabled", function() {
|
||||
spyOn(app.views.SearchBase.prototype, "setupCustomSearch");
|
||||
this.view = new app.views.SearchBase({el: "#search_people_form", typeaheadInput: $("#q"), customSearch: true});
|
||||
expect(app.views.SearchBase.prototype.setupCustomSearch).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls setupTypeahead", function() {
|
||||
spyOn(app.views.SearchBase.prototype, "setupTypeahead");
|
||||
new app.views.SearchBase({el: "#search_people_form"});
|
||||
this.view = new app.views.SearchBase({el: "#search_people_form", typeaheadInput: $("#q")});
|
||||
expect(app.views.SearchBase.prototype.setupTypeahead).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls bindSelectionEvents", function(){
|
||||
spyOn(app.views.SearchBase.prototype, "bindSelectionEvents");
|
||||
new app.views.SearchBase({el: "#search_people_form"});
|
||||
expect(app.views.SearchBase.prototype.bindSelectionEvents).toHaveBeenCalled();
|
||||
it("calls setupMouseSelectionEvents", function() {
|
||||
spyOn(app.views.SearchBase.prototype, "setupMouseSelectionEvents");
|
||||
this.view = new app.views.SearchBase({el: "#search_people_form", typeaheadInput: $("#q")});
|
||||
expect(app.views.SearchBase.prototype.setupMouseSelectionEvents).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("initializes the results to filter", function(){
|
||||
spyOn(app.views.SearchBase.prototype, "bindSelectionEvents");
|
||||
var view = new app.views.SearchBase({el: "#search_people_form"});
|
||||
expect(view.resultsTofilter.length).toBe(0);
|
||||
it("initializes the array of diaspora ids that should be excluded from the search results", function() {
|
||||
this.view = new app.views.SearchBase({el: "#search_people_form", typeaheadInput: $("#q")});
|
||||
expect(this.view.ignoreDiasporaIds.length).toBe(0);
|
||||
});
|
||||
|
||||
it("doesn't call setupAutoselect if autoselect hasn't been enabled", function() {
|
||||
spyOn(app.views.SearchBase.prototype, "setupAutoselect");
|
||||
this.view = new app.views.SearchBase({el: "#search_people_form", typeaheadInput: $("#q")});
|
||||
expect(app.views.SearchBase.prototype.setupAutoselect).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls setupAutoselect if autoselect has been enabled", function() {
|
||||
spyOn(app.views.SearchBase.prototype, "setupAutoselect");
|
||||
this.view = new app.views.SearchBase({el: "#search_people_form", typeaheadInput: $("#q"), autoselect: true});
|
||||
expect(app.views.SearchBase.prototype.setupAutoselect).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("setupBloodhound", function(){
|
||||
beforeEach(function(){
|
||||
this.view = new app.views.SearchBase({el: "#search_people_form"});
|
||||
this.syncCallback = function(){};
|
||||
this.asyncCallback = function(){};
|
||||
describe("setupCustomSearch", function() {
|
||||
it("sets bloodhound.customSearch", function() {
|
||||
this.view = new app.views.SearchBase({el: "#search_people_form", typeaheadInput: $("#q")});
|
||||
expect(this.view.bloodhound.customSearch).toBeUndefined();
|
||||
this.view.setupCustomSearch();
|
||||
expect(this.view.bloodhound.customSearch).toBeDefined();
|
||||
});
|
||||
|
||||
context("when performing a local search with 1 filtered result", function(){
|
||||
beforeEach(function(){
|
||||
this.view.initialize({typeaheadElement: this.view.$("#q")});
|
||||
this.view.bloodhound.add([
|
||||
{"id":1,"guid":"1","name":"user1","handle":"user1@pod.tld","url":"/people/1"},
|
||||
{"id":2,"guid":"2","name":"user2","handle":"user2@pod.tld","url":"/people/2"}
|
||||
]);
|
||||
describe("customSearch", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.SearchBase({
|
||||
el: "#search_people_form",
|
||||
typeaheadInput: $("#q"),
|
||||
customSearch: true
|
||||
});
|
||||
this.view.bloodhound.add(this.bloodhoundData);
|
||||
});
|
||||
|
||||
it("should not return the filtered result", function(){
|
||||
spyOn(this, "syncCallback");
|
||||
spyOn(this, "asyncCallback");
|
||||
it("returns all results if none of them should be ignored", function() {
|
||||
var spy = jasmine.createSpyObj("callbacks", ["syncCallback", "asyncCallback"]);
|
||||
this.view.bloodhound.customSearch("user", spy.syncCallback, spy.asyncCallback);
|
||||
expect(spy.syncCallback).toHaveBeenCalledWith(this.bloodhoundData);
|
||||
});
|
||||
|
||||
this.view.bloodhound.customSearch("user", this.syncCallback, this.asyncCallback);
|
||||
expect(this.syncCallback).toHaveBeenCalledWith([
|
||||
{"id":1,"guid":"1","name":"user1","handle":"user1@pod.tld","url":"/people/1"},
|
||||
{"id":2,"guid":"2","name":"user2","handle":"user2@pod.tld","url":"/people/2"}
|
||||
]);
|
||||
expect(this.asyncCallback).not.toHaveBeenCalled();
|
||||
|
||||
this.view.addToFilteredResults({"id":1,"guid":"1","name":"user1","handle":"user1@pod.tld","url":"/people/1"});
|
||||
this.view.bloodhound.customSearch("user", this.syncCallback, this.asyncCallback);
|
||||
expect(this.syncCallback).toHaveBeenCalledWith(
|
||||
[{"id":2,"guid":"2","name":"user2","handle":"user2@pod.tld","url":"/people/2"}]);
|
||||
expect(this.asyncCallback).not.toHaveBeenCalled();
|
||||
it("doesn't return results that should be ignored", function() {
|
||||
var spy = jasmine.createSpyObj("callbacks", ["syncCallback", "asyncCallback"]);
|
||||
this.view.ignorePersonForSuggestions({handle: "user1@pod.tld"});
|
||||
this.view.bloodhound.customSearch("user", spy.syncCallback, spy.asyncCallback);
|
||||
expect(spy.syncCallback).toHaveBeenCalledWith([this.bloodhoundData[1]]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("transformBloodhoundResponse", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.SearchBase({ el: "#search_people_form" });
|
||||
this.view = new app.views.SearchBase({el: "#search_people_form", typeaheadInput: $("#q")});
|
||||
});
|
||||
|
||||
context("with persons", function() {
|
||||
|
|
@ -99,81 +130,119 @@ describe("app.views.SearchBase", function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe("bindSelectionEvents", function(){
|
||||
describe("setupMouseSelectionEvents", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.SearchBase({ el: "#search_people_form" });
|
||||
this.view.initialize({typeaheadElement: this.view.$("#q")});
|
||||
this.view.bloodhound.add([
|
||||
{"person": true, "name":"user1", "handle":"user1@pod.tld"},
|
||||
{"person": true, "name":"user2", "handle":"user2@pod.tld"}
|
||||
]);
|
||||
this.view = new app.views.SearchBase({el: "#search_people_form", typeaheadInput: $("#q")});
|
||||
this.view.bloodhound.add(this.bloodhoundData);
|
||||
});
|
||||
|
||||
context("bind over events", function(){
|
||||
it("binds over event only once", function(){
|
||||
this.view.$("#q").trigger("focusin");
|
||||
this.view.$("#q").val("user");
|
||||
this.view.$("#q").trigger("keypress");
|
||||
this.view.$("#q").trigger("input");
|
||||
this.view.$("#q").trigger("focus");
|
||||
var numBindedEvents = $._data(this.view.$(".tt-menu .tt-suggestion")[0], "events").mouseover.length;
|
||||
expect(numBindedEvents).toBe(1);
|
||||
this.view.$("#q").trigger("focusout");
|
||||
this.view.$("#q").trigger("focusin");
|
||||
this.view.$("#q").val("user");
|
||||
this.view.$("#q").trigger("keypress");
|
||||
this.view.$("#q").trigger("input");
|
||||
this.view.$("#q").trigger("focus");
|
||||
numBindedEvents = $._data(this.view.$(".tt-menu .tt-suggestion")[0], "events").mouseover.length;
|
||||
expect(numBindedEvents).toBe(1);
|
||||
});
|
||||
it("binds mouseover and mouseleave events only once", function() {
|
||||
this.search(this.view, "user");
|
||||
$("#q").trigger("focusout");
|
||||
expect($._data($(".tt-menu .tt-suggestion")[0], "events").mouseover.length).toBe(1);
|
||||
expect($._data($(".tt-menu .tt-suggestion")[0], "events").mouseout.length).toBe(1);
|
||||
|
||||
it("highlights the result when overing it", function(){
|
||||
this.view.$("#q").trigger("focusin");
|
||||
this.view.$("#q").val("user");
|
||||
this.view.$("#q").trigger("keypress");
|
||||
this.view.$("#q").trigger("input");
|
||||
this.view.$("#q").trigger("focus");
|
||||
this.view.$(".tt-menu .tt-suggestion").first().trigger("mouseover");
|
||||
expect(this.view.$(".tt-menu .tt-suggestion").first()).toHaveClass("tt-cursor");
|
||||
});
|
||||
this.search(this.view, "user");
|
||||
$("#q").trigger("focusout");
|
||||
expect($._data($(".tt-menu .tt-suggestion")[0], "events").mouseover.length).toBe(1);
|
||||
expect($._data($(".tt-menu .tt-suggestion")[0], "events").mouseout.length).toBe(1);
|
||||
});
|
||||
|
||||
it("allows selecting results with the mouse", function() {
|
||||
this.search(this.view, "user");
|
||||
this.view.$(".tt-menu .tt-suggestion:eq(0)").trigger("mouseover");
|
||||
expect(this.view.$(".tt-menu .tt-suggestion:eq(0)")).toHaveClass("tt-cursor");
|
||||
expect(this.view.$(".tt-cursor").length).toBe(1);
|
||||
|
||||
this.view.$(".tt-menu .tt-suggestion:eq(1)").trigger("mouseover");
|
||||
expect(this.view.$(".tt-menu .tt-suggestion:eq(1)")).toHaveClass("tt-cursor");
|
||||
expect(this.view.$(".tt-cursor").length).toBe(1);
|
||||
|
||||
this.view.$(".tt-menu .tt-suggestion:eq(1)").trigger("mouseleave");
|
||||
expect(this.view.$(".tt-cursor").length).toBe(0);
|
||||
|
||||
this.view.$(".tt-menu .tt-suggestion:eq(0)").trigger("mouseover");
|
||||
expect(this.view.$(".tt-menu .tt-suggestion:eq(0)")).toHaveClass("tt-cursor");
|
||||
expect(this.view.$(".tt-cursor").length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("addToFilteredResults", function(){
|
||||
describe("_deselectAllSuggestions", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.SearchBase({ el: "#search_people_form" });
|
||||
this.view.initialize({typeaheadElement: this.view.$("#q")});
|
||||
this.view = new app.views.SearchBase({el: "#search_people_form", typeaheadInput: $("#q")});
|
||||
this.view.bloodhound.add(this.bloodhoundData);
|
||||
this.search(this.view, "user");
|
||||
});
|
||||
|
||||
context("when item is a person", function(){
|
||||
it("add the item to filtered results", function(){
|
||||
this.view.addToFilteredResults({handle: "user@pod.tld"});
|
||||
expect(this.view.resultsTofilter.length).toBe(1);
|
||||
});
|
||||
});
|
||||
it("deselects all suggestions", function() {
|
||||
$(".tt-suggestion").addClass(".tt-cursor");
|
||||
this.view._deselectAllSuggestions();
|
||||
expect($(".tt-suggestion.tt-cursor").length).toBe(0);
|
||||
|
||||
context("when item is not a person", function(){
|
||||
it("does not add the item to filtered results", function(){
|
||||
this.view.addToFilteredResults({});
|
||||
expect(this.view.resultsTofilter.length).toBe(0);
|
||||
});
|
||||
$(".tt-suggestion:eq(1)").addClass(".tt-cursor");
|
||||
this.view._deselectAllSuggestions();
|
||||
expect($(".tt-suggestion.tt-cursor").length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("clearFilteredResults", function(){
|
||||
describe("_selectSuggestion", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.SearchBase({ el: "#search_people_form" });
|
||||
this.view.initialize({typeaheadElement: this.view.$("#q")});
|
||||
this.view = new app.views.SearchBase({el: "#search_people_form", typeaheadInput: $("#q")});
|
||||
this.view.bloodhound.add(this.bloodhoundData);
|
||||
this.search(this.view, "user");
|
||||
});
|
||||
|
||||
context("clear filtered results", function(){
|
||||
it("clears the filtered results list", function(){
|
||||
this.view.addToFilteredResults({handle: "user@pod.tld"});
|
||||
expect(this.view.resultsTofilter.length).toBe(1);
|
||||
this.view.clearFilteredResults();
|
||||
expect(this.view.resultsTofilter.length).toBe(0);
|
||||
it("selects a suggestion", function() {
|
||||
this.view._selectSuggestion($(".tt-suggestion:eq(1)"));
|
||||
expect($(".tt-suggestion.tt-cursor").length).toBe(1);
|
||||
expect($(".tt-suggestion:eq(1)")).toHaveClass("tt-cursor");
|
||||
});
|
||||
|
||||
it("deselects all other suggestions", function() {
|
||||
spyOn(this.view, "_deselectAllSuggestions").and.callThrough();
|
||||
$(".tt-suggestion:eq(0)").addClass(".tt-cursor");
|
||||
this.view._selectSuggestion($(".tt-suggestion:eq(1)"));
|
||||
expect(this.view._deselectAllSuggestions).toHaveBeenCalled();
|
||||
expect($(".tt-suggestion.tt-cursor").length).toBe(1);
|
||||
expect($(".tt-suggestion:eq(1)")).toHaveClass("tt-cursor");
|
||||
});
|
||||
});
|
||||
|
||||
describe("setupAutoSelect", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.SearchBase({
|
||||
el: "#search_people_form",
|
||||
typeaheadInput: $("#q"),
|
||||
autoselect: true
|
||||
});
|
||||
this.view.bloodhound.add(this.bloodhoundData);
|
||||
});
|
||||
|
||||
it("selects the first suggestion when showing the results", function() {
|
||||
this.search(this.view, "user");
|
||||
expect($(".tt-suggestion:eq(0)")).toHaveClass("tt-cursor");
|
||||
expect($(".tt-suggestion:eq(1)")).not.toHaveClass("tt-cursor");
|
||||
});
|
||||
});
|
||||
|
||||
describe("ignorePersonForSuggestions", function() {
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.SearchBase({el: "#search_people_form", typeaheadInput: $("#q")});
|
||||
});
|
||||
|
||||
it("adds the diaspora ids to the ignore list", function() {
|
||||
expect(this.view.ignoreDiasporaIds.length).toBe(0);
|
||||
this.view.ignorePersonForSuggestions({handle: "user1@pod.tld"});
|
||||
expect(this.view.ignoreDiasporaIds.length).toBe(1);
|
||||
this.view.ignorePersonForSuggestions({handle: "user2@pod.tld", someData: true});
|
||||
expect(this.view.ignoreDiasporaIds.length).toBe(2);
|
||||
expect(this.view.ignoreDiasporaIds).toEqual(["user1@pod.tld", "user2@pod.tld"]);
|
||||
});
|
||||
|
||||
it("doesn't fail when the diaspora id is missing", function() {
|
||||
expect(this.view.ignoreDiasporaIds.length).toBe(0);
|
||||
this.view.ignorePersonForSuggestions({data: "user1@pod.tld"});
|
||||
expect(this.view.ignoreDiasporaIds.length).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,64 +1,22 @@
|
|||
describe("app.views.Search", function(){
|
||||
beforeEach(function(){
|
||||
describe("app.views.Search", function() {
|
||||
beforeEach(function() {
|
||||
spec.content().html(
|
||||
"<form action='/search' id='search_people_form'><input id='q' name='q' type='search'/></form>"
|
||||
);
|
||||
});
|
||||
|
||||
describe("initialize", function(){
|
||||
it("calls app.views.SearchBase.prototype.initialize", function(){
|
||||
spyOn(app.views.SearchBase.prototype, "initialize").and.callThrough();
|
||||
var view = new app.views.Search({el: "#search_people_form"});
|
||||
expect(app.views.SearchBase.prototype.initialize)
|
||||
.toHaveBeenCalledWith({typeaheadElement: view.getTypeaheadElement()});
|
||||
describe("initialize", function() {
|
||||
it("calls app.views.SearchBase.prototype.initialize", function() {
|
||||
spyOn(app.views.SearchBase.prototype, "initialize");
|
||||
this.view = new app.views.Search({el: "#search_people_form"});
|
||||
var call = app.views.SearchBase.prototype.initialize.calls.mostRecent();
|
||||
expect(call.args[0].typeaheadInput.selector).toBe("#search_people_form #q");
|
||||
expect(call.args[0].remoteRoute).toBe("/search");
|
||||
});
|
||||
|
||||
it("calls bindMoreSelectionEvents", function(){
|
||||
spyOn(app.views.Search.prototype, "bindMoreSelectionEvents").and.callThrough();
|
||||
new app.views.Search({el: "#search_people_form"});
|
||||
expect(app.views.Search.prototype.bindMoreSelectionEvents).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("bindMoreSelectionEvents", function(){
|
||||
beforeEach(function() {
|
||||
this.view = new app.views.Search({ el: "#search_people_form" });
|
||||
this.view.bloodhound.add([
|
||||
{"person": true, "name":"user1", "handle":"user1@pod.tld"},
|
||||
{"person": true, "name":"user2", "handle":"user2@pod.tld"}
|
||||
]);
|
||||
});
|
||||
|
||||
context("bind mouseleave event", function(){
|
||||
it("binds mouseleave event only once", function(){
|
||||
this.view.$("#q").trigger("focusin");
|
||||
this.view.$("#q").val("user");
|
||||
this.view.$("#q").trigger("keypress");
|
||||
this.view.$("#q").trigger("input");
|
||||
this.view.$("#q").trigger("focus");
|
||||
var numBindedEvents = $._data(this.view.$(".tt-menu")[0], "events").mouseout.length;
|
||||
expect(numBindedEvents).toBe(1);
|
||||
this.view.$("#q").trigger("focusout");
|
||||
this.view.$("#q").trigger("focusin");
|
||||
this.view.$("#q").val("user");
|
||||
this.view.$("#q").trigger("keypress");
|
||||
this.view.$("#q").trigger("input");
|
||||
this.view.$("#q").trigger("focus");
|
||||
numBindedEvents = $._data(this.view.$(".tt-menu")[0], "events").mouseout.length;
|
||||
expect(numBindedEvents).toBe(1);
|
||||
});
|
||||
|
||||
it("remove result highlight when leaving results list", function(){
|
||||
this.view.$("#q").trigger("focusin");
|
||||
this.view.$("#q").val("user");
|
||||
this.view.$("#q").trigger("keypress");
|
||||
this.view.$("#q").trigger("input");
|
||||
this.view.$("#q").trigger("focus");
|
||||
this.view.$(".tt-menu .tt-suggestion").first().trigger("mouseover");
|
||||
expect(this.view.$(".tt-menu .tt-suggestion").first()).toHaveClass("tt-cursor");
|
||||
this.view.$(".tt-menu").first().trigger("mouseleave");
|
||||
expect(this.view.$(".tt-menu .tt-cursor").length).toBe(0);
|
||||
});
|
||||
it("binds typeahead:select", function() {
|
||||
this.view = new app.views.Search({el: "#search_people_form"});
|
||||
expect($._data($("#q")[0], "events")["typeahead:select"].length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue