Merge pull request #7302 from svbergerem/simplify-mentions-publisher
Simplify mentions in the publisher
This commit is contained in:
commit
f1f1d09944
17 changed files with 123 additions and 316 deletions
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
* Make the mention syntax more flexible [#7305](https://github.com/diaspora/diaspora/pull/7305)
|
* Make the mention syntax more flexible [#7305](https://github.com/diaspora/diaspora/pull/7305)
|
||||||
* Display @ before mentions [#7324](https://github.com/diaspora/diaspora/pull/7324)
|
* Display @ before mentions [#7324](https://github.com/diaspora/diaspora/pull/7324)
|
||||||
|
* Simplify mentions in the publisher [#7302](https://github.com/diaspora/diaspora/pull/7302)
|
||||||
|
|
||||||
## Bug fixes
|
## Bug fixes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,29 +2,19 @@
|
||||||
|
|
||||||
app.views.PublisherMention = app.views.SearchBase.extend({
|
app.views.PublisherMention = app.views.SearchBase.extend({
|
||||||
triggerChar: "@",
|
triggerChar: "@",
|
||||||
invisibleChar: "\u200B", // zero width space
|
|
||||||
mentionRegex: /@([^@\s]+)$/,
|
mentionRegex: /@([^@\s]+)$/,
|
||||||
|
mentionSyntaxTemplate: function(person) { return "@{" + person.handle + "}"; },
|
||||||
templates: {
|
|
||||||
mentionItemSyntax: _.template("@{<%= name %> ; <%= handle %>}"),
|
|
||||||
mentionItemHighlight: _.template("<strong><span><%= name %></span></strong>")
|
|
||||||
},
|
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
"keydown #status_message_fake_text": "onInputBoxKeyDown",
|
"keydown #status_message_text": "onInputBoxKeyDown",
|
||||||
"input #status_message_fake_text": "onInputBoxInput",
|
"input #status_message_text": "updateTypeaheadInput",
|
||||||
"click #status_message_fake_text": "onInputBoxClick",
|
"click #status_message_text": "onInputBoxClick",
|
||||||
"blur #status_message_fake_text": "onInputBoxBlur"
|
"blur #status_message_text": "onInputBoxBlur"
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
this.mentionedPeople = [];
|
this.mentionedPeople = [];
|
||||||
|
this.inputBox = this.$("#status_message_text");
|
||||||
// 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.typeaheadInput = this.$(".typeahead-mention-box");
|
||||||
this.bindTypeaheadEvents();
|
this.bindTypeaheadEvents();
|
||||||
|
|
||||||
|
|
@ -55,8 +45,8 @@ app.views.PublisherMention = app.views.SearchBase.extend({
|
||||||
cleanMentionedPeople: function() {
|
cleanMentionedPeople: function() {
|
||||||
var inputText = this.inputBox.val();
|
var inputText = this.inputBox.val();
|
||||||
this.mentionedPeople = this.mentionedPeople.filter(function(person) {
|
this.mentionedPeople = this.mentionedPeople.filter(function(person) {
|
||||||
return person.name && inputText.indexOf(person.name) > -1;
|
return person.handle && inputText.indexOf(this.mentionSyntaxTemplate(person)) > -1;
|
||||||
});
|
}.bind(this));
|
||||||
this.ignoreDiasporaIds = this.mentionedPeople.map(function(person) { return person.handle; });
|
this.ignoreDiasporaIds = this.mentionedPeople.map(function(person) { return person.handle; });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -70,41 +60,16 @@ app.views.PublisherMention = app.views.SearchBase.extend({
|
||||||
this.addPersonToMentions(person);
|
this.addPersonToMentions(person);
|
||||||
this.closeSuggestions();
|
this.closeSuggestions();
|
||||||
|
|
||||||
messageText = messageText.substring(0, triggerCharPosition) +
|
var mentionText = this.mentionSyntaxTemplate(person);
|
||||||
this.invisibleChar + person.name + messageText.substring(caretPosition);
|
|
||||||
|
messageText = messageText.substring(0, triggerCharPosition) + mentionText + messageText.substring(caretPosition);
|
||||||
|
|
||||||
this.inputBox.val(messageText);
|
this.inputBox.val(messageText);
|
||||||
this.updateMessageTexts();
|
|
||||||
|
|
||||||
this.inputBox.focus();
|
this.inputBox.focus();
|
||||||
var newCaretPosition = triggerCharPosition + person.name.length + 1;
|
var newCaretPosition = triggerCharPosition + mentionText.length;
|
||||||
this.inputBox[0].setSelectionRange(newCaretPosition, newCaretPosition);
|
this.inputBox[0].setSelectionRange(newCaretPosition, newCaretPosition);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
updateMessageTexts: function() {
|
|
||||||
var fakeMessageText = this.inputBox.val(),
|
|
||||||
mentionBoxText = _.escape(fakeMessageText),
|
|
||||||
messageText = fakeMessageText;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
this.inputBox.data("messageText", messageText);
|
|
||||||
this.mentionsBox.find(".mentions").html(mentionBoxText);
|
|
||||||
},
|
|
||||||
|
|
||||||
updateTypeaheadInput: function() {
|
updateTypeaheadInput: function() {
|
||||||
var messageText = this.inputBox.val();
|
var messageText = this.inputBox.val();
|
||||||
var caretPosition = this.inputBox[0].selectionStart;
|
var caretPosition = this.inputBox[0].selectionStart;
|
||||||
|
|
@ -115,6 +80,8 @@ app.views.PublisherMention = app.views.SearchBase.extend({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.cleanMentionedPeople();
|
||||||
|
|
||||||
// result[1] is the string between the last '@' and the current caret position
|
// result[1] is the string between the last '@' and the current caret position
|
||||||
this.typeaheadInput.typeahead("val", result[1]);
|
this.typeaheadInput.typeahead("val", result[1]);
|
||||||
this.typeaheadInput.typeahead("open");
|
this.typeaheadInput.typeahead("open");
|
||||||
|
|
@ -128,12 +95,11 @@ app.views.PublisherMention = app.views.SearchBase.extend({
|
||||||
prefillMention: function(persons) {
|
prefillMention: function(persons) {
|
||||||
persons.forEach(function(person) {
|
persons.forEach(function(person) {
|
||||||
this.addPersonToMentions(person);
|
this.addPersonToMentions(person);
|
||||||
var text = this.invisibleChar + person.name;
|
var text = this.mentionSyntaxTemplate(person);
|
||||||
if(this.inputBox.val().length !== 0) {
|
if(this.inputBox.val().length !== 0) {
|
||||||
text = this.inputBox.val() + " " + text;
|
text = this.inputBox.val() + " " + text;
|
||||||
}
|
}
|
||||||
this.inputBox.val(text);
|
this.inputBox.val(text);
|
||||||
this.updateMessageTexts();
|
|
||||||
}, this);
|
}, this);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -154,15 +120,6 @@ app.views.PublisherMention = app.views.SearchBase.extend({
|
||||||
this.typeaheadInput.trigger($.Event("keydown", {keyCode: e.keyCode, which: e.which}));
|
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.cleanMentionedPeople();
|
|
||||||
this.updateMessageTexts();
|
|
||||||
this.updateTypeaheadInput();
|
|
||||||
},
|
|
||||||
|
|
||||||
onInputBoxKeyDown: function(e) {
|
onInputBoxKeyDown: function(e) {
|
||||||
// This also matches HOME/END on OSX which is CMD+LEFT, CMD+RIGHT
|
// This also matches HOME/END on OSX which is CMD+LEFT, CMD+RIGHT
|
||||||
if(e.which === Keycodes.LEFT || e.which === Keycodes.RIGHT ||
|
if(e.which === Keycodes.LEFT || e.which === Keycodes.RIGHT ||
|
||||||
|
|
@ -205,7 +162,7 @@ app.views.PublisherMention = app.views.SearchBase.extend({
|
||||||
|
|
||||||
reset: function() {
|
reset: function() {
|
||||||
this.inputBox.val("");
|
this.inputBox.val("");
|
||||||
this.onInputBoxInput();
|
this.updateTypeaheadInput();
|
||||||
},
|
},
|
||||||
|
|
||||||
closeSuggestions: function() {
|
closeSuggestions: function() {
|
||||||
|
|
@ -217,7 +174,8 @@ app.views.PublisherMention = app.views.SearchBase.extend({
|
||||||
return this.$(".tt-menu").is(":visible");
|
return this.$(".tt-menu").is(":visible");
|
||||||
},
|
},
|
||||||
|
|
||||||
getTextForSubmit: function() {
|
getMentionedPeople: function() {
|
||||||
return this.mentionedPeople.length ? this.inputBox.data("messageText") : this.inputBox.val();
|
this.cleanMentionedPeople();
|
||||||
|
return this.mentionedPeople;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,11 @@ app.views.Publisher = Backbone.View.extend({
|
||||||
el : "#publisher",
|
el : "#publisher",
|
||||||
|
|
||||||
events : {
|
events : {
|
||||||
"keydown #status_message_fake_text" : "keyDown",
|
"keydown #status_message_text": "keyDown",
|
||||||
"focus textarea" : "open",
|
"focus textarea" : "open",
|
||||||
"submit form" : "createStatusMessage",
|
"submit form" : "createStatusMessage",
|
||||||
"click #submit" : "createStatusMessage",
|
"click #submit" : "createStatusMessage",
|
||||||
"textchange #status_message_fake_text": "handleTextchange",
|
"textchange #status_message_text": "checkSubmitAvailability",
|
||||||
"click #locator" : "showLocation",
|
"click #locator" : "showLocation",
|
||||||
"click #poll_creator" : "togglePollCreator",
|
"click #poll_creator" : "togglePollCreator",
|
||||||
"click #hide_location" : "destroyLocation",
|
"click #hide_location" : "destroyLocation",
|
||||||
|
|
@ -35,8 +35,7 @@ app.views.Publisher = Backbone.View.extend({
|
||||||
this.disabled = false;
|
this.disabled = false;
|
||||||
|
|
||||||
// init shortcut references to the various elements
|
// init shortcut references to the various elements
|
||||||
this.inputEl = this.$("#status_message_fake_text");
|
this.inputEl = this.$("#status_message_text");
|
||||||
this.hiddenInputEl = this.$("#status_message_text");
|
|
||||||
this.wrapperEl = this.$("#publisher_textarea_wrapper");
|
this.wrapperEl = this.$("#publisher_textarea_wrapper");
|
||||||
this.submitEl = this.$("input[type=submit], button#submit");
|
this.submitEl = this.$("input[type=submit], button#submit");
|
||||||
this.photozoneEl = this.$("#photodropzone");
|
this.photozoneEl = this.$("#photodropzone");
|
||||||
|
|
@ -46,14 +45,6 @@ app.views.Publisher = Backbone.View.extend({
|
||||||
$(window).on("beforeunload", _.bind(this._beforeUnload, this));
|
$(window).on("beforeunload", _.bind(this._beforeUnload, this));
|
||||||
$(window).unload(this.clear.bind(this));
|
$(window).unload(this.clear.bind(this));
|
||||||
|
|
||||||
// sync textarea content
|
|
||||||
if( this.hiddenInputEl.val() === "" ) {
|
|
||||||
this.hiddenInputEl.val( this.inputEl.val() );
|
|
||||||
}
|
|
||||||
if( this.inputEl.val() === "" ) {
|
|
||||||
this.inputEl.val( this.hiddenInputEl.val() );
|
|
||||||
}
|
|
||||||
|
|
||||||
// hide close and preview buttons and manage services link
|
// hide close and preview buttons and manage services link
|
||||||
// in case publisher is standalone
|
// in case publisher is standalone
|
||||||
// (e.g. bookmarklet, mentions popup)
|
// (e.g. bookmarklet, mentions popup)
|
||||||
|
|
@ -163,7 +154,7 @@ app.views.Publisher = Backbone.View.extend({
|
||||||
this.viewPollCreator.render();
|
this.viewPollCreator.render();
|
||||||
|
|
||||||
if (this.prefillMention) {
|
if (this.prefillMention) {
|
||||||
this.handleTextchange();
|
this.checkSubmitAvailability();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -175,12 +166,11 @@ app.views.Publisher = Backbone.View.extend({
|
||||||
// inject content into the publisher textarea
|
// inject content into the publisher textarea
|
||||||
setText: function(txt) {
|
setText: function(txt) {
|
||||||
this.inputEl.val(txt);
|
this.inputEl.val(txt);
|
||||||
this.hiddenInputEl.val(txt);
|
|
||||||
this.prefillText = txt;
|
this.prefillText = txt;
|
||||||
|
|
||||||
this.inputEl.trigger("input");
|
this.inputEl.trigger("input");
|
||||||
autosize.update(this.inputEl);
|
autosize.update(this.inputEl);
|
||||||
this.handleTextchange();
|
this.checkSubmitAvailability();
|
||||||
},
|
},
|
||||||
|
|
||||||
// show the "getting started" popups around the publisher
|
// show the "getting started" popups around the publisher
|
||||||
|
|
@ -202,9 +192,6 @@ app.views.Publisher = Backbone.View.extend({
|
||||||
// empty poll answer and failing validation.
|
// empty poll answer and failing validation.
|
||||||
this.viewPollCreator.removeLastAnswer();
|
this.viewPollCreator.removeLastAnswer();
|
||||||
|
|
||||||
//add missing mentions at end of post:
|
|
||||||
this.handleTextchange();
|
|
||||||
|
|
||||||
var serializedForm = $(evt.target).closest("form").serializeObject();
|
var serializedForm = $(evt.target).closest("form").serializeObject();
|
||||||
// disable input while posting, must be after the form is serialized
|
// disable input while posting, must be after the form is serialized
|
||||||
this.setInputEnabled(false);
|
this.setInputEnabled(false);
|
||||||
|
|
@ -255,7 +242,7 @@ app.views.Publisher = Backbone.View.extend({
|
||||||
self.setButtonsEnabled(true);
|
self.setButtonsEnabled(true);
|
||||||
self.setInputEnabled(true);
|
self.setInputEnabled(true);
|
||||||
self.wrapperEl.removeClass("submitting");
|
self.wrapperEl.removeClass("submitting");
|
||||||
self.handleTextchange();
|
self.checkSubmitAvailability();
|
||||||
autosize.update(self.inputEl);
|
autosize.update(self.inputEl);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -330,13 +317,8 @@ app.views.Publisher = Backbone.View.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
createPostPreview: function() {
|
createPostPreview: function() {
|
||||||
//add missing mentions at end of post:
|
|
||||||
this.handleTextchange();
|
|
||||||
|
|
||||||
var serializedForm = $("#new_status_message").serializeObject();
|
var serializedForm = $("#new_status_message").serializeObject();
|
||||||
var text = this.mention.getTextForSubmit();
|
|
||||||
var photos = this.getUploadedPhotos();
|
var photos = this.getUploadedPhotos();
|
||||||
var mentionedPeople = this.mention.mentionedPeople;
|
|
||||||
var poll = this.getPollData(serializedForm);
|
var poll = this.getPollData(serializedForm);
|
||||||
var locationCoords = serializedForm["location[coords]"];
|
var locationCoords = serializedForm["location[coords]"];
|
||||||
if(!locationCoords || locationCoords === "") {
|
if(!locationCoords || locationCoords === "") {
|
||||||
|
|
@ -352,12 +334,12 @@ app.views.Publisher = Backbone.View.extend({
|
||||||
|
|
||||||
var previewMessage = {
|
var previewMessage = {
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"text": text,
|
"text": serializedForm["status_message[text]"],
|
||||||
"public": serializedForm["aspect_ids[]"] === "public",
|
"public": serializedForm["aspect_ids[]"] === "public",
|
||||||
"created_at": new Date().toISOString(),
|
"created_at": new Date().toISOString(),
|
||||||
"interacted_at": new Date().toISOString(),
|
"interacted_at": new Date().toISOString(),
|
||||||
"author": app.currentUser ? app.currentUser.attributes : {},
|
"author": app.currentUser ? app.currentUser.attributes : {},
|
||||||
"mentioned_people": mentionedPeople,
|
"mentioned_people": this.mention.getMentionedPeople(),
|
||||||
"photos": photos,
|
"photos": photos,
|
||||||
"title": serializedForm["status_message[text]"],
|
"title": serializedForm["status_message[text]"],
|
||||||
"location": location,
|
"location": location,
|
||||||
|
|
@ -381,11 +363,10 @@ app.views.Publisher = Backbone.View.extend({
|
||||||
// remove mentions
|
// remove mentions
|
||||||
this.mention.reset();
|
this.mention.reset();
|
||||||
|
|
||||||
// clear text(s)
|
// clear text
|
||||||
this.inputEl.val("");
|
this.inputEl.val("");
|
||||||
this.hiddenInputEl.val("");
|
|
||||||
this.inputEl.trigger("keyup")
|
this.inputEl.trigger("keyup")
|
||||||
.trigger("keydown");
|
.trigger("keydown");
|
||||||
autosize.update(this.inputEl);
|
autosize.update(this.inputEl);
|
||||||
|
|
||||||
// remove photos
|
// remove photos
|
||||||
|
|
@ -421,7 +402,6 @@ app.views.Publisher = Backbone.View.extend({
|
||||||
|
|
||||||
// force textchange plugin to update lastValue
|
// force textchange plugin to update lastValue
|
||||||
this.inputEl.data("lastValue", "");
|
this.inputEl.data("lastValue", "");
|
||||||
this.hiddenInputEl.data("lastValue", "");
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
@ -472,8 +452,7 @@ app.views.Publisher = Backbone.View.extend({
|
||||||
setEnabled: function(bool) {
|
setEnabled: function(bool) {
|
||||||
this.setInputEnabled(bool);
|
this.setInputEnabled(bool);
|
||||||
this.disabled = !bool;
|
this.disabled = !bool;
|
||||||
|
this.checkSubmitAvailability();
|
||||||
this.handleTextchange();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setButtonsEnabled: function(bool) {
|
setButtonsEnabled: function(bool) {
|
||||||
|
|
@ -487,10 +466,8 @@ app.views.Publisher = Backbone.View.extend({
|
||||||
setInputEnabled: function(bool) {
|
setInputEnabled: function(bool) {
|
||||||
if (bool) {
|
if (bool) {
|
||||||
this.inputEl.removeAttr("disabled");
|
this.inputEl.removeAttr("disabled");
|
||||||
this.hiddenInputEl.removeAttr("disabled");
|
|
||||||
} else {
|
} else {
|
||||||
this.inputEl.prop("disabled", true);
|
this.inputEl.prop("disabled", true);
|
||||||
this.hiddenInputEl.prop("disabled", true);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -503,11 +480,6 @@ app.views.Publisher = Backbone.View.extend({
|
||||||
return (!onlyWhitespaces || isPhotoAttached) && isValidPoll && !this.disabled;
|
return (!onlyWhitespaces || isPhotoAttached) && isValidPoll && !this.disabled;
|
||||||
},
|
},
|
||||||
|
|
||||||
handleTextchange: function() {
|
|
||||||
this.checkSubmitAvailability();
|
|
||||||
this.hiddenInputEl.val(this.mention.getTextForSubmit());
|
|
||||||
},
|
|
||||||
|
|
||||||
_beforeUnload: function(e) {
|
_beforeUnload: function(e) {
|
||||||
if(this._submittable() && this.inputEl.val() !== this.prefillText){
|
if(this._submittable() && this.inputEl.val() !== this.prefillText){
|
||||||
var confirmationMessage = Diaspora.I18n.t("confirm_unload");
|
var confirmationMessage = Diaspora.I18n.t("confirm_unload");
|
||||||
|
|
|
||||||
|
|
@ -64,28 +64,4 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mentions-box {
|
|
||||||
position: absolute;
|
|
||||||
right: 0px;
|
|
||||||
bottom: 0px;
|
|
||||||
left: 0px;
|
|
||||||
top: 0px;
|
|
||||||
padding: $padding-base-vertical $padding-base-horizontal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mentions {
|
|
||||||
color: transparent;
|
|
||||||
font-size: $font-size-base;
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
overflow: hidden;
|
|
||||||
width: 100%;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-wrap: break-word;
|
|
||||||
|
|
||||||
> strong {
|
|
||||||
background: $background-blue;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,6 @@
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mentions-box {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#publisher_textarea_wrapper { border: 1px solid $border-grey !important; }
|
#publisher_textarea_wrapper { border: 1px solid $border-grey !important; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,8 +244,6 @@
|
||||||
.locator { display: none; }
|
.locator { display: none; }
|
||||||
}
|
}
|
||||||
|
|
||||||
&.submitting .mentions-box { display: none; }
|
|
||||||
|
|
||||||
.twitter-typeahead {
|
.twitter-typeahead {
|
||||||
left: -1px;
|
left: -1px;
|
||||||
// Override inline rule of Typeahead
|
// Override inline rule of Typeahead
|
||||||
|
|
@ -257,11 +251,6 @@
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
// scss-lint:enable ImportantRule
|
// scss-lint:enable ImportantRule
|
||||||
}
|
}
|
||||||
|
|
||||||
.mentions-box {
|
|
||||||
// Leave space for markdown editor header
|
|
||||||
margin-top: 42px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.publisher-buttonbar {
|
.publisher-buttonbar {
|
||||||
|
|
|
||||||
|
|
@ -21,16 +21,6 @@ module InterimStreamHackinessHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def publisher_hidden_text
|
|
||||||
if params[:prefill].present?
|
|
||||||
params[:prefill]
|
|
||||||
elsif defined?(@stream)
|
|
||||||
@stream.publisher.prefill
|
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def from_group(post)
|
def from_group(post)
|
||||||
if defined?(@stream) && params[:controller] == 'multis'
|
if defined?(@stream) && params[:controller] == 'multis'
|
||||||
@stream.post_from_group(post)
|
@stream.post_from_group(post)
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,17 @@
|
||||||
%params
|
%params
|
||||||
.publisher-textarea-wrapper#publisher_textarea_wrapper
|
.publisher-textarea-wrapper#publisher_textarea_wrapper
|
||||||
.mentions-input-box
|
.mentions-input-box
|
||||||
.mentions-box
|
|
||||||
.mentions
|
|
||||||
- if current_user.getting_started?
|
- if current_user.getting_started?
|
||||||
= status.text_area :fake_text, :rows => 2, :value => h(publisher_formatted_text),
|
= status.text_area :text, :rows => 2, :value => h(publisher_formatted_text),
|
||||||
:tabindex => 1, :placeholder => "#{t('contacts.index.start_a_conversation')}...",
|
:tabindex => 1, :placeholder => "#{t('contacts.index.start_a_conversation')}...",
|
||||||
"data-title" => popover_with_close_html("1. " + t("shared.public_explain.share")),
|
"data-title" => popover_with_close_html("1. " + t("shared.public_explain.share")),
|
||||||
"data-content" => t("shared.public_explain.new_user_welcome_message"),
|
"data-content" => t("shared.public_explain.new_user_welcome_message"),
|
||||||
"class" => "form-control"
|
"class" => "form-control"
|
||||||
- else
|
- else
|
||||||
= status.text_area :fake_text, :rows => 2, :value => h(publisher_formatted_text),
|
= status.text_area :text, :rows => 2, :value => h(publisher_formatted_text),
|
||||||
:tabindex => 1, :placeholder => "#{t('contacts.index.start_a_conversation')}...",
|
:tabindex => 1, :placeholder => "#{t('contacts.index.start_a_conversation')}...",
|
||||||
"class" => "form-control"
|
"class" => "form-control"
|
||||||
%input.typeahead-mention-box.hidden{type: "text"}
|
%input.typeahead-mention-box.hidden{type: "text"}
|
||||||
= status.hidden_field :text, value: h(publisher_hidden_text), class: "clear_on_submit"
|
|
||||||
|
|
||||||
.container-fluid.photodropzone-container#photodropzone_container
|
.container-fluid.photodropzone-container#photodropzone_container
|
||||||
%ul#photodropzone
|
%ul#photodropzone
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ Feature: posting
|
||||||
Then I should see a ".tag-following-action .followed"
|
Then I should see a ".tag-following-action .followed"
|
||||||
|
|
||||||
Scenario: can post a message from the tag page
|
Scenario: can post a message from the tag page
|
||||||
Then I should see "#boss" within "#publisher"
|
Then I should see "#boss " in the publisher
|
||||||
When I click the publisher and post "#boss from the tag page"
|
When I click the publisher and post "#boss from the tag page"
|
||||||
And I go to the tag page for "boss"
|
And I go to the tag page for "boss"
|
||||||
Then I should see "#boss from the tag page"
|
Then I should see "#boss from the tag page"
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ Feature: preview posts in the stream
|
||||||
Given I expand the publisher
|
Given I expand the publisher
|
||||||
And I attach "spec/fixtures/button.png" to the publisher
|
And I attach "spec/fixtures/button.png" to the publisher
|
||||||
When I fill in the following:
|
When I fill in the following:
|
||||||
| status_message_fake_text | Look at this dog |
|
| status_message_text | Look at this dog |
|
||||||
And I preview the post
|
And I preview the post
|
||||||
Then I should see a "img" within ".md-preview .stream-element .photo_attachments"
|
Then I should see a "img" within ".md-preview .stream-element .photo_attachments"
|
||||||
And I should see "Look at this dog" within ".md-preview .stream-element"
|
And I should see "Look at this dog" within ".md-preview .stream-element"
|
||||||
|
|
@ -63,7 +63,7 @@ Feature: preview posts in the stream
|
||||||
Then I should see "Samuel Beckett"
|
Then I should see "Samuel Beckett"
|
||||||
When I expand the publisher
|
When I expand the publisher
|
||||||
And I fill in the following:
|
And I fill in the following:
|
||||||
| status_message_fake_text | This preview rocks |
|
| status_message_text | This preview rocks |
|
||||||
And I preview the post
|
And I preview the post
|
||||||
Then I should see "This preview rocks" in the preview
|
Then I should see "This preview rocks" in the preview
|
||||||
And I close the publisher
|
And I close the publisher
|
||||||
|
|
@ -71,11 +71,11 @@ Feature: preview posts in the stream
|
||||||
Scenario: preview a post with the poll
|
Scenario: preview a post with the poll
|
||||||
Given I expand the publisher
|
Given I expand the publisher
|
||||||
When I fill in the following:
|
When I fill in the following:
|
||||||
| status_message_fake_text | I am eating yogurt |
|
| status_message_text | I am eating yogurt |
|
||||||
And I click on selector "#poll_creator"
|
And I click on selector "#poll_creator"
|
||||||
When I fill in the following:
|
When I fill in the following:
|
||||||
| status_message_fake_text | I am eating yogurt |
|
| status_message_text | I am eating yogurt |
|
||||||
| poll_question | What kind of yogurt do you like? |
|
| poll_question | What kind of yogurt do you like? |
|
||||||
And I fill in the following for the options:
|
And I fill in the following for the options:
|
||||||
| normal |
|
| normal |
|
||||||
| not normal |
|
| not normal |
|
||||||
|
|
@ -87,12 +87,12 @@ Feature: preview posts in the stream
|
||||||
Scenario: preview a post with location
|
Scenario: preview a post with location
|
||||||
Given I expand the publisher
|
Given I expand the publisher
|
||||||
When I fill in the following:
|
When I fill in the following:
|
||||||
| status_message_fake_text | I am eating yogurt |
|
| status_message_text | I am eating yogurt |
|
||||||
And I allow geolocation
|
And I allow geolocation
|
||||||
And I click on selector "#locator"
|
And I click on selector "#locator"
|
||||||
When I fill in the following:
|
When I fill in the following:
|
||||||
| status_message_fake_text | I am eating yogurt |
|
| status_message_text | I am eating yogurt |
|
||||||
| location_address | Some cool place |
|
| location_address | Some cool place |
|
||||||
And I preview the post
|
And I preview the post
|
||||||
Then I should see a ".near-from" within ".md-preview .stream-element"
|
Then I should see a ".near-from" within ".md-preview .stream-element"
|
||||||
And I should see "Some cool place" within ".md-preview .stream-element .near-from"
|
And I should see "Some cool place" within ".md-preview .stream-element .near-from"
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ Feature: posting with a poll
|
||||||
Given I expand the publisher
|
Given I expand the publisher
|
||||||
And I click on selector "#poll_creator"
|
And I click on selector "#poll_creator"
|
||||||
When I fill in the following:
|
When I fill in the following:
|
||||||
| status_message_fake_text | I am eating yogurt |
|
| status_message_text | I am eating yogurt |
|
||||||
| poll_question | What kind of yogurt do you like? |
|
| poll_question | What kind of yogurt do you like? |
|
||||||
And I fill in the following for the options:
|
And I fill in the following for the options:
|
||||||
| normal |
|
| normal |
|
||||||
| not normal |
|
| not normal |
|
||||||
|
|
@ -53,8 +53,8 @@ Feature: posting with a poll
|
||||||
Given I expand the publisher
|
Given I expand the publisher
|
||||||
And I click on selector "#poll_creator"
|
And I click on selector "#poll_creator"
|
||||||
When I fill in the following:
|
When I fill in the following:
|
||||||
| status_message_fake_text | I am eating yogurt |
|
| status_message_text | I am eating yogurt |
|
||||||
| poll_question | What kind of yogurt do you like? |
|
| poll_question | What kind of yogurt do you like? |
|
||||||
And I fill in the following for the options:
|
And I fill in the following for the options:
|
||||||
| normal |
|
| normal |
|
||||||
| not normal |
|
| not normal |
|
||||||
|
|
@ -70,8 +70,8 @@ Feature: posting with a poll
|
||||||
Given I expand the publisher
|
Given I expand the publisher
|
||||||
And I click on selector "#poll_creator"
|
And I click on selector "#poll_creator"
|
||||||
When I fill in the following:
|
When I fill in the following:
|
||||||
| status_message_fake_text | I am eating yogurt |
|
| status_message_text | I am eating yogurt |
|
||||||
| poll_question | What kind of yogurt do you like? |
|
| poll_question | What kind of yogurt do you like? |
|
||||||
And I fill in the following for the options:
|
And I fill in the following for the options:
|
||||||
| normal |
|
| normal |
|
||||||
| not normal |
|
| not normal |
|
||||||
|
|
@ -83,8 +83,8 @@ Feature: posting with a poll
|
||||||
Given I expand the publisher
|
Given I expand the publisher
|
||||||
And I click on selector "#poll_creator"
|
And I click on selector "#poll_creator"
|
||||||
When I fill in the following:
|
When I fill in the following:
|
||||||
| status_message_fake_text | I am eating yogurt |
|
| status_message_text | I am eating yogurt |
|
||||||
| poll_question | What kind of yogurt do you like? |
|
| poll_question | What kind of yogurt do you like? |
|
||||||
And I fill in the following for the options:
|
And I fill in the following for the options:
|
||||||
| normal |
|
| normal |
|
||||||
| |
|
| |
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ Feature: posting from the mobile main page
|
||||||
|
|
||||||
Scenario: post and delete some text
|
Scenario: post and delete some text
|
||||||
Given I visit the mobile publisher page
|
Given I visit the mobile publisher page
|
||||||
And I append "I am eating yogurt" to the mobile publisher
|
And I append "I am eating yogurt" to the publisher
|
||||||
And I select "Unicorns" from "aspect_ids_"
|
And I select "Unicorns" from "aspect_ids_"
|
||||||
And I press "Share"
|
And I press "Share"
|
||||||
When I go to the stream page
|
When I go to the stream page
|
||||||
|
|
@ -52,7 +52,7 @@ Feature: posting from the mobile main page
|
||||||
|
|
||||||
Scenario: back out of uploading a picture when another has been attached
|
Scenario: back out of uploading a picture when another has been attached
|
||||||
Given I visit the mobile publisher page
|
Given I visit the mobile publisher page
|
||||||
And I append "I am eating yogurt" to the mobile publisher
|
And I append "I am eating yogurt" to the publisher
|
||||||
And I attach the file "spec/fixtures/button.gif" to hidden "qqfile" within "#file-upload-publisher"
|
And I attach the file "spec/fixtures/button.gif" to hidden "qqfile" within "#file-upload-publisher"
|
||||||
And I attach the file "spec/fixtures/button.png" to hidden "qqfile" within "#file-upload-publisher"
|
And I attach the file "spec/fixtures/button.png" to hidden "qqfile" within "#file-upload-publisher"
|
||||||
And I click to delete the first uploaded photo
|
And I click to delete the first uploaded photo
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ When /^I press the "([^\"]*)" key somewhere$/ do |key|
|
||||||
end
|
end
|
||||||
|
|
||||||
When /^I press the "([^\"]*)" key in the publisher$/ do |key|
|
When /^I press the "([^\"]*)" key in the publisher$/ do |key|
|
||||||
find("#status_message_fake_text").native.send_key(key)
|
find("#status_message_text").native.send_key(key)
|
||||||
end
|
end
|
||||||
|
|
||||||
Then /^post (\d+) should be highlighted$/ do |position|
|
Then /^post (\d+) should be highlighted$/ do |position|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,10 @@ Then /^I should not be able to submit the publisher$/ do
|
||||||
expect(publisher_submittable?).to be false
|
expect(publisher_submittable?).to be false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Then /^I should see "([^"]*)" in the publisher$/ do |text|
|
||||||
|
expect(page).to have_field("status_message[text]", with: text)
|
||||||
|
end
|
||||||
|
|
||||||
Given /^I have a limited post with text "([^\"]*)" in the aspect "([^"]*)"$/ do |text, aspect_name|
|
Given /^I have a limited post with text "([^\"]*)" in the aspect "([^"]*)"$/ do |text, aspect_name|
|
||||||
@me.post :status_message, text: text, to: @me.aspects.where(name: aspect_name).first.id
|
@me.post :status_message, text: text, to: @me.aspects.where(name: aspect_name).first.id
|
||||||
end
|
end
|
||||||
|
|
@ -114,10 +118,6 @@ When /^I append "([^"]*)" to the publisher$/ do |text|
|
||||||
append_to_publisher(text)
|
append_to_publisher(text)
|
||||||
end
|
end
|
||||||
|
|
||||||
When /^I append "([^"]*)" to the mobile publisher$/ do |text|
|
|
||||||
append_to_publisher(text, '#status_message_text')
|
|
||||||
end
|
|
||||||
|
|
||||||
When /^I attach "([^"]*)" to the publisher$/ do |path|
|
When /^I attach "([^"]*)" to the publisher$/ do |path|
|
||||||
upload_file_with_publisher(path)
|
upload_file_with_publisher(path)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,12 @@
|
||||||
module PublishingCukeHelpers
|
module PublishingCukeHelpers
|
||||||
def write_in_publisher(txt)
|
def write_in_publisher(txt)
|
||||||
fill_in 'status_message_fake_text', with: txt
|
fill_in "status_message_text", with: txt
|
||||||
end
|
end
|
||||||
|
|
||||||
def append_to_publisher(txt, input_selector='#status_message_fake_text')
|
def append_to_publisher(txt)
|
||||||
status_message_text = find("#status_message_text", visible: false).value
|
status_message_text = find("#status_message_text").value
|
||||||
find(input_selector).native.send_key(" #{txt}")
|
find("#status_message_text").native.send_key(" #{txt}")
|
||||||
|
expect(page).to have_field("status_message[text]", with: "#{status_message_text} #{txt}")
|
||||||
# make sure the other text field got the new contents
|
|
||||||
if input_selector == "#status_message_fake_text"
|
|
||||||
begin
|
|
||||||
expect(page).to have_selector("#status_message_text[value='#{status_message_text} #{txt}']", visible: false)
|
|
||||||
rescue RSpec::Expectations::ExpectationNotMetError
|
|
||||||
puts "Value was instead: #{find('#status_message_text', visible: false).value.inspect}"
|
|
||||||
raise
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def upload_file_with_publisher(path)
|
def upload_file_with_publisher(path)
|
||||||
|
|
@ -33,7 +24,7 @@ module PublishingCukeHelpers
|
||||||
end
|
end
|
||||||
|
|
||||||
def submit_publisher
|
def submit_publisher
|
||||||
txt = find("#publisher #status_message_fake_text").value
|
txt = find("#publisher #status_message_text").value
|
||||||
find("#publisher .btn-primary").click
|
find("#publisher .btn-primary").click
|
||||||
# wait for the content to appear
|
# wait for the content to appear
|
||||||
expect(find("#main_stream")).to have_content(txt)
|
expect(find("#main_stream")).to have_content(txt)
|
||||||
|
|
@ -45,7 +36,7 @@ module PublishingCukeHelpers
|
||||||
end
|
end
|
||||||
|
|
||||||
def click_publisher
|
def click_publisher
|
||||||
find("#status_message_fake_text").click
|
find("#status_message_text").click
|
||||||
expect(find("#publisher")).to have_css(".publisher-textarea-wrapper.active")
|
expect(find("#publisher")).to have_css(".publisher-textarea-wrapper.active")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,23 +29,18 @@ describe("app.views.Bookmarklet", function() {
|
||||||
|
|
||||||
it("prefills the publisher", function() {
|
it("prefills the publisher", function() {
|
||||||
init_bookmarklet(test_data);
|
init_bookmarklet(test_data);
|
||||||
|
|
||||||
expect($.trim(app.publisher.inputEl.val())).not.toEqual("");
|
expect($.trim(app.publisher.inputEl.val())).not.toEqual("");
|
||||||
expect($.trim(app.publisher.hiddenInputEl.val())).not.toEqual("");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("handles dirty input well", function() {
|
it("handles dirty input well", function() {
|
||||||
init_bookmarklet(evil_test_data);
|
init_bookmarklet(evil_test_data);
|
||||||
|
|
||||||
expect($.trim(app.publisher.inputEl.val())).not.toEqual("");
|
expect($.trim(app.publisher.inputEl.val())).not.toEqual("");
|
||||||
expect($.trim(app.publisher.hiddenInputEl.val())).not.toEqual("");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("allows changing a prefilled publisher", function() {
|
it("allows changing a prefilled publisher", function() {
|
||||||
init_bookmarklet(test_data);
|
init_bookmarklet(test_data);
|
||||||
app.publisher.setText(app.publisher.inputEl.val()+"A");
|
app.publisher.setText(app.publisher.inputEl.val()+"A");
|
||||||
|
expect(app.publisher.inputEl.val()).toMatch(/.+A$/);
|
||||||
expect(app.publisher.hiddenInputEl.val()).toMatch(/.+A$/);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps the publisher disabled after successful post creation", function() {
|
it("keeps the publisher disabled after successful post creation", function() {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ describe("app.views.PublisherMention", function() {
|
||||||
it("initializes object properties", function() {
|
it("initializes object properties", function() {
|
||||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||||
expect(this.view.mentionedPeople).toEqual([]);
|
expect(this.view.mentionedPeople).toEqual([]);
|
||||||
expect(this.view.invisibleChar).toBe("\u200B");
|
|
||||||
expect(this.view.triggerChar).toBe("@");
|
expect(this.view.triggerChar).toBe("@");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -29,6 +28,17 @@ describe("app.views.PublisherMention", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("mentionSyntaxTemplate", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
this.view = new app.views.PublisherMention({el: "#publisher"});
|
||||||
|
this.person = {handle: "alice@pod.tld", name: "Alice Awesome"};
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns the correct mention syntax", function() {
|
||||||
|
expect(this.view.mentionSyntaxTemplate(this.person)).toBe("@{alice@pod.tld}");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("bindTypeaheadEvents", function() {
|
describe("bindTypeaheadEvents", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||||
|
|
@ -92,30 +102,30 @@ describe("app.views.PublisherMention", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("removes person from mentioned people if not mentioned anymore", function() {
|
it("removes person from mentioned people if not mentioned anymore", function() {
|
||||||
this.view.addPersonToMentions({name: "user1", handle: "user1@pod.tld"});
|
this.view.addPersonToMentions({name: "User Name", handle: "user1@pod.tld"});
|
||||||
expect(this.view.mentionedPeople.length).toBe(1);
|
expect(this.view.mentionedPeople.length).toBe(1);
|
||||||
this.view.cleanMentionedPeople();
|
this.view.cleanMentionedPeople();
|
||||||
expect(this.view.mentionedPeople.length).toBe(0);
|
expect(this.view.mentionedPeople.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("removes person from ignored people if not mentioned anymore", function() {
|
it("removes person from ignored people if not mentioned anymore", function() {
|
||||||
this.view.addPersonToMentions({name: "user1", handle: "user1@pod.tld"});
|
this.view.addPersonToMentions({name: "User Name", handle: "user1@pod.tld"});
|
||||||
expect(this.view.ignoreDiasporaIds.length).toBe(1);
|
expect(this.view.ignoreDiasporaIds.length).toBe(1);
|
||||||
this.view.cleanMentionedPeople();
|
this.view.cleanMentionedPeople();
|
||||||
expect(this.view.ignoreDiasporaIds.length).toBe(0);
|
expect(this.view.ignoreDiasporaIds.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps mentioned persons", function() {
|
it("keeps mentioned persons", function() {
|
||||||
this.view.addPersonToMentions({name: "user1", handle: "user1@pod.tld"});
|
this.view.addPersonToMentions({name: "User Name", handle: "user1@pod.tld"});
|
||||||
this.view.inputBox.val("user1");
|
this.view.inputBox.val("@{user1@pod.tld}");
|
||||||
expect(this.view.mentionedPeople.length).toBe(1);
|
expect(this.view.mentionedPeople.length).toBe(1);
|
||||||
this.view.cleanMentionedPeople();
|
this.view.cleanMentionedPeople();
|
||||||
expect(this.view.mentionedPeople.length).toBe(1);
|
expect(this.view.mentionedPeople.length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps mentioned persons for ignored diaspora ids", function() {
|
it("keeps mentioned persons for ignored diaspora ids", function() {
|
||||||
this.view.addPersonToMentions({name: "user1", handle: "user1@pod.tld"});
|
this.view.addPersonToMentions({name: "User Name", handle: "user1@pod.tld"});
|
||||||
this.view.inputBox.val("user1");
|
this.view.inputBox.val("@{user1@pod.tld}");
|
||||||
expect(this.view.ignoreDiasporaIds.length).toBe(1);
|
expect(this.view.ignoreDiasporaIds.length).toBe(1);
|
||||||
this.view.cleanMentionedPeople();
|
this.view.cleanMentionedPeople();
|
||||||
expect(this.view.ignoreDiasporaIds.length).toBe(1);
|
expect(this.view.ignoreDiasporaIds.length).toBe(1);
|
||||||
|
|
@ -151,61 +161,29 @@ describe("app.views.PublisherMention", function() {
|
||||||
|
|
||||||
it("correctly formats the text", function() {
|
it("correctly formats the text", function() {
|
||||||
this.view.onSuggestionSelection({name: "user1337", handle: "user1@pod.tld"});
|
this.view.onSuggestionSelection({name: "user1337", handle: "user1@pod.tld"});
|
||||||
expect(this.view.inputBox.val()).toBe("@user1337 Text before \u200Buser1337 text after");
|
expect(this.view.inputBox.val()).toBe("@user1337 Text before @{user1@pod.tld} text after");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("replaces the correct mention", function() {
|
it("replaces the correct mention", function() {
|
||||||
this.view.inputBox.val("@user1337 123 user2 @user2 456 @user3 789");
|
this.view.inputBox.val("@user1337 123 user2 @user2 456 @user3 789");
|
||||||
this.view.inputBox[0].setSelectionRange(26, 26);
|
this.view.inputBox[0].setSelectionRange(26, 26);
|
||||||
this.view.onSuggestionSelection({name: "user23", handle: "user2@pod.tld"});
|
this.view.onSuggestionSelection({name: "user23", handle: "user2@pod.tld"});
|
||||||
expect(this.view.inputBox.val()).toBe("@user1337 123 user2 \u200Buser23 456 @user3 789");
|
expect(this.view.inputBox.val()).toBe("@user1337 123 user2 @{user2@pod.tld} 456 @user3 789");
|
||||||
this.view.inputBox[0].setSelectionRange(9, 9);
|
this.view.inputBox[0].setSelectionRange(9, 9);
|
||||||
this.view.onSuggestionSelection({name: "user1337", handle: "user1@pod.tld"});
|
this.view.onSuggestionSelection({name: "user1337", handle: "user1@pod.tld"});
|
||||||
expect(this.view.inputBox.val()).toBe("\u200Buser1337 123 user2 \u200Buser23 456 @user3 789");
|
expect(this.view.inputBox.val()).toBe("@{user1@pod.tld} 123 user2 @{user2@pod.tld} 456 @user3 789");
|
||||||
this.view.inputBox[0].setSelectionRange(38, 38);
|
this.view.inputBox[0].setSelectionRange(54, 54);
|
||||||
this.view.onSuggestionSelection({name: "user32", handle: "user3@pod.tld"});
|
this.view.onSuggestionSelection({name: "user32", handle: "user3@pod.tld"});
|
||||||
expect(this.view.inputBox.val()).toBe("\u200Buser1337 123 user2 \u200Buser23 456 \u200Buser32 789");
|
expect(this.view.inputBox.val()).toBe("@{user1@pod.tld} 123 user2 @{user2@pod.tld} 456 @{user3@pod.tld} 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() {
|
it("places the caret at the right position", function() {
|
||||||
this.view.onSuggestionSelection({"name": "user1WithLongName", "handle": "user1@pod.tld"});
|
this.view.onSuggestionSelection({"name": "user1WithLongName", "handle": "user1@pod.tld"});
|
||||||
var expectedCaretPosition = ("@user1337 Text before \u200Buser1WithLongName").length;
|
var expectedCaretPosition = ("@user1337 Text before @{user1@pod.tld}").length;
|
||||||
expect(this.view.inputBox[0].selectionStart).toBe(expectedCaretPosition);
|
expect(this.view.inputBox[0].selectionStart).toBe(expectedCaretPosition);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("updateMessageTexts", function() {
|
|
||||||
beforeEach(function() {
|
|
||||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
|
||||||
this.view.inputBox.val("@user1 Text before \u200Buser1\ntext after");
|
|
||||||
this.view.mentionedPeople.push({"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 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");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("properly escapes the user input", function() {
|
|
||||||
this.view.inputBox.val("<img src=\"/default.png\"> @user1 Text before \u200Buser1\ntext after");
|
|
||||||
this.view.updateMessageTexts();
|
|
||||||
expect(this.view.mentionsBox.find(".mentions").html())
|
|
||||||
.toBe("<img src=\"/default.png\"> @user1 Text before <strong><span>user1</span></strong>\ntext after");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("updateTypeaheadInput", function() {
|
describe("updateTypeaheadInput", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||||
|
|
@ -251,20 +229,34 @@ describe("app.views.PublisherMention", function() {
|
||||||
expect(this.view.closeSuggestions).not.toHaveBeenCalled();
|
expect(this.view.closeSuggestions).not.toHaveBeenCalled();
|
||||||
expect(this.view.typeaheadInput.val()).toBe("user");
|
expect(this.view.typeaheadInput.val()).toBe("user");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("doesn't call 'cleanMentionedPeople' if there is no '@' in front of the caret", function() {
|
||||||
|
spyOn(this.view, "cleanMentionedPeople");
|
||||||
|
this.view.inputBox.val("user1337 Text before @user1 text after");
|
||||||
|
this.view.inputBox[0].setSelectionRange(9, 9);
|
||||||
|
this.view.updateTypeaheadInput();
|
||||||
|
expect(this.view.cleanMentionedPeople).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls 'cleanMentionedPeople' if there is an '@' in front of the caret", function() {
|
||||||
|
spyOn(this.view, "cleanMentionedPeople");
|
||||||
|
this.view.inputBox.val("@user1337 Text before @user1 text after");
|
||||||
|
this.view.inputBox[0].setSelectionRange(9, 9);
|
||||||
|
this.view.updateTypeaheadInput();
|
||||||
|
expect(this.view.cleanMentionedPeople).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("prefillMention", function() {
|
describe("prefillMention", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||||
spyOn(this.view, "addPersonToMentions");
|
spyOn(this.view, "addPersonToMentions");
|
||||||
spyOn(this.view, "updateMessageTexts");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("prefills one mention", function() {
|
it("prefills one mention", function() {
|
||||||
this.view.prefillMention([{"name": "user1", "handle": "user1@pod.tld"}]);
|
this.view.prefillMention([{"name": "user1", "handle": "user1@pod.tld"}]);
|
||||||
expect(this.view.addPersonToMentions).toHaveBeenCalledWith({"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("@{user1@pod.tld}");
|
||||||
expect(this.view.inputBox.val()).toBe("\u200Buser1");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("prefills multiple mentions", function() {
|
it("prefills multiple mentions", function() {
|
||||||
|
|
@ -275,8 +267,7 @@ describe("app.views.PublisherMention", function() {
|
||||||
|
|
||||||
expect(this.view.addPersonToMentions).toHaveBeenCalledWith({"name": "user1", "handle": "user1@pod.tld"});
|
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.addPersonToMentions).toHaveBeenCalledWith({"name": "user2", "handle": "user2@pod.tld"});
|
||||||
expect(this.view.updateMessageTexts).toHaveBeenCalled();
|
expect(this.view.inputBox.val()).toBe("@{user1@pod.tld} @{user2@pod.tld}");
|
||||||
expect(this.view.inputBox.val()).toBe("\u200Buser1 \u200Buser2");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -372,30 +363,6 @@ describe("app.views.PublisherMention", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("onInputBoxInput", function() {
|
|
||||||
beforeEach(function() {
|
|
||||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
|
||||||
});
|
|
||||||
|
|
||||||
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() {
|
describe("onInputBoxClick", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||||
|
|
@ -423,13 +390,13 @@ describe("app.views.PublisherMention", function() {
|
||||||
describe("reset", function() {
|
describe("reset", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
||||||
spyOn(this.view, "onInputBoxInput");
|
spyOn(this.view, "updateTypeaheadInput");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("resets the mention box", function() {
|
it("resets the mention box", function() {
|
||||||
this.view.reset();
|
this.view.reset();
|
||||||
expect(this.view.inputBox.val()).toBe("");
|
expect(this.view.inputBox.val()).toBe("");
|
||||||
expect(this.view.onInputBoxInput).toHaveBeenCalled();
|
expect(this.view.updateTypeaheadInput).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -454,27 +421,21 @@ describe("app.views.PublisherMention", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("getTextForSubmit", function() {
|
describe("getMentionedPeople", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.view = new app.views.PublisherMention({ el: "#publisher" });
|
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 if someone has been mentioned", function() {
|
it("calls 'cleanMentionedPeople'", function() {
|
||||||
this.view.inputBox.val("@user");
|
spyOn(this.view, "cleanMentionedPeople");
|
||||||
this.view.inputBox[0].setSelectionRange(5, 5);
|
this.view.getMentionedPeople();
|
||||||
this.view.typeaheadInput.typeahead("val", "user");
|
expect(this.view.cleanMentionedPeople).toHaveBeenCalled();
|
||||||
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 has been mentioned", function() {
|
it("returns the cleaned mentionedPeople", function() {
|
||||||
this.view.inputBox.data("messageText", "Bad text");
|
this.view.inputBox.val("@{user1@pod.tld} user2@pod.tld");
|
||||||
this.view.inputBox.val("Good text");
|
this.view.mentionedPeople = [{name: "user1", handle: "user1@pod.tld"}, {name: "user2", handle: "user2@pod.tld"}];
|
||||||
expect(this.view.getTextForSubmit()).toBe("Good text");
|
expect(this.view.getMentionedPeople()).toEqual([{name: "user1", handle: "user1@pod.tld"}]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -43,17 +43,11 @@ describe("app.views.Publisher", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#initSubviews", function() {
|
describe("#initSubviews", function() {
|
||||||
it("calls handleTextchange if the publisher is prefilled with mentions", function() {
|
it("calls checkSubmitAvailability if the publisher is prefilled with mentions", function() {
|
||||||
spyOn(this.view, "handleTextchange");
|
spyOn(this.view, "checkSubmitAvailability");
|
||||||
this.view.prefillMention = "user@example.org";
|
this.view.prefillMention = "user@example.org";
|
||||||
this.view.initSubviews();
|
this.view.initSubviews();
|
||||||
expect(this.view.handleTextchange).toHaveBeenCalled();
|
expect(this.view.checkSubmitAvailability).toHaveBeenCalled();
|
||||||
});
|
|
||||||
|
|
||||||
it("doesn't call handleTextchange if there are no prefilled mentions", function() {
|
|
||||||
spyOn(this.view, "handleTextchange");
|
|
||||||
this.view.initSubviews();
|
|
||||||
expect(this.view.handleTextchange).not.toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -82,9 +76,9 @@ describe("app.views.Publisher", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("resets the element's height", function() {
|
it("resets the element's height", function() {
|
||||||
$(this.view.el).find("#status_message_fake_text").height(100);
|
$(this.view.el).find("#status_message_text").height(100);
|
||||||
this.view.close($.Event());
|
this.view.close($.Event());
|
||||||
expect($(this.view.el).find("#status_message_fake_text").attr("style")).not.toContain("height");
|
expect($(this.view.el).find("#status_message_text").attr("style")).not.toContain("height");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("calls autosize.update", function() {
|
it("calls autosize.update", function() {
|
||||||
|
|
@ -203,12 +197,6 @@ describe("app.views.Publisher", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("createStatusMessage", function(){
|
describe("createStatusMessage", function(){
|
||||||
it("calls handleTextchange to complete missing mentions", function(){
|
|
||||||
spyOn(this.view, "handleTextchange");
|
|
||||||
this.view.createStatusMessage($.Event());
|
|
||||||
expect(this.view.handleTextchange).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("adds the status message to the stream", function() {
|
it("adds the status message to the stream", function() {
|
||||||
app.stream = { addNow: $.noop };
|
app.stream = { addNow: $.noop };
|
||||||
spyOn(app.stream, "addNow");
|
spyOn(app.stream, "addNow");
|
||||||
|
|
@ -224,20 +212,10 @@ describe("app.views.Publisher", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("createPostPreview", function(){
|
|
||||||
it("calls handleTextchange to complete missing mentions", function(){
|
|
||||||
spyOn(this.view, "handleTextchange");
|
|
||||||
this.view.createPostPreview();
|
|
||||||
expect(this.view.handleTextchange).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#setText', function() {
|
describe('#setText', function() {
|
||||||
it("sets the content text", function() {
|
it("sets the content text", function() {
|
||||||
this.view.setText("FOO bar");
|
this.view.setText("FOO bar");
|
||||||
|
|
||||||
expect(this.view.inputEl.val()).toEqual("FOO bar");
|
expect(this.view.inputEl.val()).toEqual("FOO bar");
|
||||||
expect(this.view.hiddenInputEl.val()).toEqual("FOO bar");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -248,7 +226,6 @@ describe("app.views.Publisher", function() {
|
||||||
|
|
||||||
expect(this.view.disabled).toBeTruthy();
|
expect(this.view.disabled).toBeTruthy();
|
||||||
expect(this.view.inputEl.prop("disabled")).toBeTruthy();
|
expect(this.view.inputEl.prop("disabled")).toBeTruthy();
|
||||||
expect(this.view.hiddenInputEl.prop("disabled")).toBeTruthy();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("disables submitting", function() {
|
it("disables submitting", function() {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue