mention js working minus tracking keypresses with the hidden message field.

This commit is contained in:
danielvincent 2011-02-04 17:26:21 -08:00 committed by Raphael Sofaer
parent 7d21f7bfdd
commit 3efc31c68f
4 changed files with 153 additions and 60 deletions

View file

@ -160,7 +160,7 @@ class Person < ActiveRecord::Base
end
def as_json(opts={})
{:id => self.guid, :name => self.name, :avatar => self.profile.image_url(:thumb_small), :url => "/people/#{self.id}"}
{:id => self.guid, :name => self.name, :avatar => self.profile.image_url(:thumb_small), :handle => self.diaspora_handle, :url => "/people/#{self.id}"}
end
protected

View file

@ -37,7 +37,7 @@ class StatusMessage < Post
identifiers = self.message.scan(regex).map do |match|
match.last
end
Person.where(:diaspora_handle => identifiers)
self.person.owner.contact_people.where(:diaspora_handle => identifiers)
end
def to_activity

View file

@ -36,11 +36,6 @@ var Publisher = {
return Publisher.cachedHiddenInput;
},
appendToHiddenField: function(evt){
Publisher.hiddenInput().val(
Publisher.input().val());
},
autocompletion: {
options : function(){return {
minChars : 1,
@ -58,13 +53,71 @@ var Publisher = {
return row.name;
}
};},
onSelect : function(input, data, formatted) {
addMentionToVisibleInput(input, formatted);
hiddenMentionFromPerson : function(personData){
return "@{" + personData.name + "; " + personData.handle + "}";
},
addMentionToVisibleInput: function(input, formatted){
var cursorIndex = input[0].selectionStart;
onSelect : function(visibleInput, data, formatted) {
var visibleCursorIndex = visibleInput[0].selectionStart;
var visibleLoc = Publisher.autocompletion.addMentionToInput(visibleInput, visibleCursorIndex, formatted);
var hiddenCursorIndex = visibleCursorIndex + Publisher.autocompletion.mentionList.offsetFrom(visibleCursorIndex);
var hiddenLoc = Publisher.autocompletion.addMentionToInput(Publisher.hiddenInput(), hiddenCursorIndex, Publisher.autocompletion.hiddenMentionFromPerson(data));
var mention = { visibleStart: visibleLoc[0],
visibleEnd : visibleLoc[1],
hiddenStart : hiddenLoc[0],
hiddenEnd : hiddenLoc[1]
};
},
mentionList : {
mentions : [],
push : function(mention){
mention.offset = mention.hiddenEnd - mention.visibleEnd;
this.mentions.push(mention);
},
keypressAt : function(visibleCursorIndex){
var mentionIndex = this.mentionAt(visibleCursorIndex);
var mention = this.mentions[mentionIndex];
if(!mention){return;}
var visibleMentionString = Publisher.input().val().slice(mention.visibleStart, mention.visibleEnd);
var hiddenContent = Publisher.hiddenInput().val();
hiddenContent = hiddenContent.slice(0,mention.hiddenStart) +
visibleMentionString +
hiddenContent.slice(mention.hiddenEnd);
Publisher.hiddenInput().val(hiddenContent);
this.mentions.splice(mentionIndex, 1);
},
mentionAt : function(visibleCursorIndex){
for(i in this.mentions){
var mention = this.mentions[i];
if(visibleCursorIndex >= mention.visibleStart && visibleCursorIndex < mention.visibleEnd){
return i;
}
return false;
}
},
offsetFrom: function(visibleCursorIndex){
var mention = {visibleStart : -1, fake: true};
var currentMention;
for(i in this.mentions){
currentMention = this.mentions[i];
if(visibleCursorIndex >= currentMention.visibleStart &&
currentMention.visibleStart > mention.visibleStart){
mention = currentMention;
}
}
if(mention && !mention.fake){
return mention.offset;
}else{
return 0;
}
}
},
addMentionToInput: function(input, cursorIndex, formatted){
var inputContent = input.val();
var stringLoc = Publisher.autocompletion.findStringToReplace(input.val(), cursorIndex);
@ -73,12 +126,13 @@ var Publisher = {
var stringEnd = inputContent.slice(stringLoc[1]);
input.val(stringStart + formatted + stringEnd);
return [stringStart.length, stringStart.length + stringLoc[1]]
},
findStringToReplace: function(value, cursorIndex){
var atLocation = value.lastIndexOf('@', cursorIndex);
if(atLocation == -1){return [0,0];}
var nextAt = value.indexOf('@', cursorIndex+1);
var nextAt = value.indexOf(' @', cursorIndex+1);
if(nextAt == -1){nextAt = value.length;}
return [atLocation, nextAt];
@ -115,6 +169,7 @@ var Publisher = {
initialize: function() {
Publisher.cachedForm = false;
Publisher.cachedInput = false;
Publisher.cachedHiddenInput = false;
$("div.public_toggle input").live("click", function(evt) {
$("#publisher_service_icons").toggleClass("dim");
if ($(this).attr('checked') == true) {
@ -127,9 +182,7 @@ var Publisher = {
};
Publisher.autocompletion.initialize();
Publisher.updateHiddenField();
Publisher.form().find('#status_message_fake_message').bind('keydown',
Publisher.updateHiddenField);
Publisher.hiddenInput().val(Publisher.input().val());
Publisher.form().find("textarea").bind("focus", function(evt) {
Publisher.open();
$(this).css('min-height', '42px');

View file

@ -6,21 +6,6 @@
describe("Publisher", function() {
describe("initialize", function(){
it("calls updateHiddenField", function(){
spec.loadFixture('aspects_index_prefill');
spyOn(Publisher, 'updateHiddenField');
Publisher.initialize();
expect(Publisher.updateHiddenField).toHaveBeenCalled();
});
it("attaches updateHiddenField to the keydown handler on fake_message", function(){
spec.loadFixture('aspects_index_prefill');
spyOn(Publisher, 'updateHiddenField');
Publisher.initialize();
Publisher.form().find('#status_message_fake_message').keydown();
expect(Publisher.updateHiddenField.mostRecentCall.args[0].type).toBe('keydown');
});
it("calls close when it does not have text", function(){
spec.loadFixture('aspects_index');
spyOn(Publisher, 'close');
@ -67,17 +52,6 @@ describe("Publisher", function() {
expect(Publisher.form().find(".options_and_submit:visible").length).toBe(0);
});
});
describe("updateHiddenField", function(){
beforeEach(function(){
spec.loadFixture('aspects_index_prefill');
});
it("copies the value of fake_message to message",function(){
Publisher.updateHiddenField();
expect(Publisher.form().find('#status_message_message').val()).toBe(
Publisher.form().find('#status_message_fake_message').val());
});
});
describe("input", function(){
beforeEach(function(){
spec.loadFixture('aspects_index_prefill');
@ -88,6 +62,8 @@ describe("Publisher", function() {
});
});
describe("autocompletion", function(){
describe("onKeypress", function(){
});,
describe("searchTermFromValue", function(){
var func;
beforeEach(function(){func = Publisher.autocompletion.searchTermFromValue;});
@ -124,56 +100,120 @@ describe("Publisher", function() {
describe("onSelect", function(){
});
describe("addMentionToHiddenInput", function(){
var func;
var input;
describe("mentionList", function(){
var visibleInput, visibleVal,
hiddenInput, hiddenVal,
list,
func,
mention;
beforeEach(function(){
spec.loadFixture('aspects_index');
func = Publisher.autocompletion.addMentionToHiddenInput;
input = Publisher.input();
list = Publisher.autocompletion.mentionList;
func = list.keypressAt;
visibleInput = Publisher.input();
hiddenInput = Publisher.hiddenInput();
mention = { visibleStart : 0,
visibleEnd : 5,
hiddenStart : 0,
hiddenEnd : 21
};
list.mentions = [];
list.push(mention);
visibleVal = "Danny loves testing javascript";
visibleInput.val(visibleVal);
hiddenVal = "@{Danny; dan@pod.org} loves testing javascript";
hiddenInput.val(hiddenVal);
});
describe("push", function(){
it("adds mention to mentions array", function(){
expect(list.mentions.length).toBe(1);
expect(list.mentions[0]).toBe(mention)
});
});
describe("mentionAt", function(){
it("returns the location of the mention at that location in the mentions array", function(){
expect(list.mentions[list.mentionAt(3)]).toBe(mention);
});
it("returns null if there is no mention", function(){
expect(list.mentionAt(8)).toBeFalsy();
});
});
describe("keypressAt", function(){
it("does nothing if there is no visible mention at that index", function(){
list.keypressAt(8);
expect(visibleInput.val()).toBe(visibleVal)
expect(hiddenInput.val()).toBe(hiddenVal)
});
it("deletes the mention from the hidden field if there is a mention", function(){
list.keypressAt(3);
expect(visibleInput.val()).toBe(visibleVal)
expect(hiddenInput.val()).toBe(visibleVal)
});
it("deletes the mention from the list", function(){
list.keypressAt(3);
expect(list.mentionAt(3)).toBeFalsy();
});
it("updates the offsets of the remaining mentions in the list");
});
describe("offsetFrom", function(){
var func;
beforeEach(function(){
func = list.offsetFrom;
});
it("returns the offset of the mention at that location", function(){
expect(list.offsetFrom(3)).toBe(mention.offset);
});
it("returns the offset of the previous mention if there is no mention there", function(){
expect(list.offsetFrom(10)).toBe(mention.offset);
});
it("returns 0 if there are no mentions", function(){
list.mentions = [];
expect(list.offsetFrom(8)).toBe(0);
});
});
});
describe("addMentionToVisibleInput", function(){
describe("addMentionToInput", function(){
var func;
var input;
var replaceWith;
beforeEach(function(){
spec.loadFixture('aspects_index');
func = Publisher.autocompletion.addMentionToVisibleInput;
func = Publisher.autocompletion.addMentionToInput;
input = Publisher.input();
replaceWith = "Replace with this.";
});
it("replaces everything after an @ if the cursor is a word after that @", function(){
input.val('not @dan grip');
func(input, replaceWith);
input[0].selectionStart = 13;
var cursorIndex = 13;
func(input, cursorIndex, replaceWith);
expect(input.val()).toBe('not ' + replaceWith);
});
it("replaces everything after an @ if the cursor is after that @", function(){
input.val('not @dan grip');
input[0].selectionStart = 7;
func(input, replaceWith);
var cursorIndex = 7;
func(input, cursorIndex, replaceWith);
expect(input.val()).toBe('not ' + replaceWith);
});
it("replaces everything after an @ at the start of the line", function(){
input.val('@dan grip');
input[0].selectionStart = 9;
func(input, replaceWith);
var cursorIndex = 9;
func(input, cursorIndex, replaceWith);
expect(input.val()).toBe(replaceWith);
});
it("replaces everything between @s if there are 2 @s and the cursor is between them", function(){
input.val('@asdpo aoisdj @asodk');
input[0].selectionStart = 8;
func(input, replaceWith);
var cursorIndex = 8;
func(input, cursorIndex, replaceWith);
expect(input.val()).toBe(replaceWith + ' @asodk');
});
it("replaces everything after the 2nd @ if there are 2 @s and the cursor after them", function(){
input.val('@asod asdo @asd asok');
input[0].selectionStart = 15;
func(input, replaceWith);
var cursorIndex = 15;
func(input, cursorIndex, replaceWith);
expect(input.val()).toBe('@asod asdo ' + replaceWith);
});
});