diaspora/public/javascripts/publisher.js
zhitomirskiyi abbf949fe1 publishing from a person profile page wip
mentioning a person from their profile page, added js & jasmine, still need to add the mention style, and prevent deselecting the last one

a tiny sass add

publishing from the profile works, need js translation

added the translation

made the hover state consistant

need to fix the cucumber spec

specs are green need to add a button

added the buttion to mention people

moved the publisher to the facebox

fixed the cucumbers for the modal window
2011-03-16 16:35:30 -07:00

355 lines
12 KiB
JavaScript

/* Copyright (c) 2010, Diaspora Inc. This file is
* licensed under the Affero General Public License version 3 or later. See
* the COPYRIGHT file.
*/
//TODO: make this a widget
var Publisher = {
close: function(){
Publisher.form().addClass('closed');
Publisher.form().find("textarea.ac_input").css('min-height', '');
},
open: function(){
Publisher.form().removeClass('closed');
Publisher.form().find("textarea.ac_input").css('min-height', '42px');
Publisher.determineSubmitAvailability();
},
cachedForm : false,
form: function(){
if(!Publisher.cachedForm){
Publisher.cachedForm = $('#publisher');
}
return Publisher.cachedForm;
},
cachedInput : false,
input: function(){
if(!Publisher.cachedInput){
Publisher.cachedInput = Publisher.form().find('#status_message_fake_text');
}
return Publisher.cachedInput;
},
cachedSubmit : false,
submit: function(){
if(!Publisher.cachedSubmit){
Publisher.cachedSubmit = Publisher.form().find('#status_message_submit');
}
return Publisher.cachedSubmit;
},
cachedHiddenInput : false,
hiddenInput: function(){
if(!Publisher.cachedHiddenInput){
Publisher.cachedHiddenInput = Publisher.form().find('#status_message_text');
}
return Publisher.cachedHiddenInput;
},
cachedSubmit : false,
submit: function(){
if(!Publisher.cachedSubmit){
Publisher.cachedSubmit = Publisher.form().find('#status_message_submit');
}
return Publisher.cachedSubmit;
},
autocompletion: {
options : function(){return {
minChars : 1,
max : 5,
onSelect : Publisher.autocompletion.onSelect,
searchTermFromValue: Publisher.autocompletion.searchTermFromValue,
scroll : false,
formatItem: function(row, i, max) {
return "<img src='"+ row.avatar +"' class='avatar'/>" + row.name;
},
formatMatch: function(row, i, max) {
return row.name;
},
formatResult: function(row) {
return row.name;
},
disableRightAndLeft : true
};},
hiddenMentionFromPerson : function(personData){
return "@{" + personData.name + "; " + personData.handle + "}";
},
onSelect : function(visibleInput, data, formatted) {
var visibleCursorIndex = visibleInput[0].selectionStart;
var visibleLoc = Publisher.autocompletion.addMentionToInput(visibleInput, visibleCursorIndex, formatted);
$.Autocompleter.Selection(visibleInput[0], visibleLoc[1], visibleLoc[1]);
var mentionString = Publisher.autocompletion.hiddenMentionFromPerson(data);
var mention = { visibleStart: visibleLoc[0],
visibleEnd : visibleLoc[1],
mentionString : mentionString
};
Publisher.autocompletion.mentionList.push(mention);
Publisher.oldInputContent = visibleInput.val();
Publisher.hiddenInput().val(Publisher.autocompletion.mentionList.generateHiddenInput(visibleInput.val()));
},
mentionList : {
mentions : [],
sortedMentions : function(){
return this.mentions.sort(function(m1, m2){
if(m1.visibleStart > m2.visibleStart){
return -1;
} else if(m1.visibleStart < m2.visibleStart){
return 1;
} else {
return 0;
}
});
},
push : function(mention){
this.mentions.push(mention);
},
generateHiddenInput : function(visibleString){
var resultString = visibleString;
for(i in this.sortedMentions()){
var mention = this.mentions[i];
var start = resultString.slice(0, mention.visibleStart);
var insertion = mention.mentionString;
var end = resultString.slice(mention.visibleEnd);
resultString = start + insertion + end;
}
return resultString;
},
insertionAt : function(insertionStartIndex, selectionEnd, keyCode){
if(insertionStartIndex != selectionEnd){
this.selectionDeleted(insertionStartIndex, selectionEnd);
}
this.updateMentionLocations(insertionStartIndex, 1);
this.destroyMentionAt(insertionStartIndex);
},
deletionAt : function(selectionStart, selectionEnd, keyCode){
if(selectionStart != selectionEnd){
this.selectionDeleted(selectionStart, selectionEnd);
return;
}
var effectiveCursorIndex;
if(keyCode == KEYCODES.DEL){
effectiveCursorIndex = selectionStart;
}else{
effectiveCursorIndex = selectionStart - 1;
}
this.updateMentionLocations(effectiveCursorIndex, -1);
this.destroyMentionAt(effectiveCursorIndex);
},
selectionDeleted : function(selectionStart, selectionEnd){
Publisher.autocompletion.mentionList.destroyMentionsWithin(selectionStart, selectionEnd);
Publisher.autocompletion.mentionList.updateMentionLocations(selectionStart, selectionStart - selectionEnd);
},
destroyMentionsWithin : function(start, end){
for (var i = this.mentions.length - 1; i >= 0; i--){
var mention = this.mentions[i];
if(start < mention.visibleEnd && end >= mention.visibleStart){
this.mentions.splice(i, 1);
}
}
},
clear: function(){
this.mentions = [];
},
destroyMentionAt : function(effectiveCursorIndex){
var mentionIndex = this.mentionAt(effectiveCursorIndex);
var mention = this.mentions[mentionIndex];
if(mention){
this.mentions.splice(mentionIndex, 1);
}
},
updateMentionLocations : function(effectiveCursorIndex, offset){
var changedMentions = this.mentionsAfter(effectiveCursorIndex);
for(i in changedMentions){
var mention = changedMentions[i];
mention.visibleStart += offset;
mention.visibleEnd += offset;
}
},
mentionAt : function(visibleCursorIndex){
for(i in this.mentions){
var mention = this.mentions[i];
if(visibleCursorIndex > mention.visibleStart && visibleCursorIndex < mention.visibleEnd){
return i;
}
}
return false;
},
mentionsAfter : function(visibleCursorIndex){
var resultMentions = [];
for(i in this.mentions){
var mention = this.mentions[i];
if(visibleCursorIndex <= mention.visibleStart){
resultMentions.push(mention);
}
}
return resultMentions;
},
},
repopulateHiddenInput: function(){
var newHiddenVal = Publisher.autocompletion.mentionList.generateHiddenInput(Publisher.input().val());
if(newHiddenVal != Publisher.hiddenInput().val()){
Publisher.hiddenInput().val(newHiddenVal);
}
},
keyUpHandler : function(event){
Publisher.autocompletion.repopulateHiddenInput();
Publisher.determineSubmitAvailability();
},
keyDownHandler : function(event){
var input = Publisher.input();
var selectionStart = input[0].selectionStart;
var selectionEnd = input[0].selectionEnd;
var isDeletion = (event.keyCode == KEYCODES.DEL && selectionStart < input.val().length) || (event.keyCode == KEYCODES.BACKSPACE && (selectionStart > 0 || selectionStart != selectionEnd))
var isInsertion = (KEYCODES.isInsertion(event.keyCode) && event.keyCode != KEYCODES.RETURN )
if(isDeletion){
Publisher.autocompletion.mentionList.deletionAt(selectionStart, selectionEnd, event.keyCode);
}else if(isInsertion){
Publisher.autocompletion.mentionList.insertionAt(selectionStart, selectionEnd, event.keyCode);
}
},
addMentionToInput: function(input, cursorIndex, formatted){
var inputContent = input.val();
var stringLoc = Publisher.autocompletion.findStringToReplace(inputContent, cursorIndex);
var stringStart = inputContent.slice(0, stringLoc[0]);
var stringEnd = inputContent.slice(stringLoc[1]);
input.val(stringStart + formatted + stringEnd);
var offset = formatted.length - (stringLoc[1] - stringLoc[0])
Publisher.autocompletion.mentionList.updateMentionLocations(stringStart.length, offset);
return [stringStart.length, stringStart.length + formatted.length]
},
findStringToReplace: function(value, cursorIndex){
var atLocation = value.lastIndexOf('@', cursorIndex);
if(atLocation == -1){return [0,0];}
var nextAt = cursorIndex
if(nextAt == -1){nextAt = value.length;}
return [atLocation, nextAt];
},
searchTermFromValue: function(value, cursorIndex)
{
var stringLoc = Publisher.autocompletion.findStringToReplace(value, cursorIndex);
if(stringLoc[0] <= 2){
stringLoc[0] = 0;
}else{
stringLoc[0] -= 2
}
var relevantString = value.slice(stringLoc[0], stringLoc[1]).replace(/\s+$/,"");
var matches = relevantString.match(/(^|\s)@(.+)/);
if(matches){
return matches[2];
}else{
return '';
}
},
contactsJSON: function(){
return $.parseJSON($('#contact_json').val());
},
initialize: function(){
Publisher.input().autocomplete(Publisher.autocompletion.contactsJSON(),
Publisher.autocompletion.options());
Publisher.input().result(Publisher.autocompletion.selectItemCallback);
Publisher.oldInputContent = Publisher.input().val();
}
},
determineSubmitAvailability: function(){
var onlyWhitespaces = (Publisher.input().val().trim() == '');
var isSubmitDisabled = Publisher.submit().attr('disabled');
if (onlyWhitespaces && !isSubmitDisabled) {
Publisher.submit().attr('disabled', true);
} else if (!onlyWhitespaces && isSubmitDisabled) {
Publisher.submit().removeAttr('disabled');
}
},
clear: function(){
this.autocompletion.mentionList.clear();
$("#photodropzone").find('li').remove();
$("#publisher textarea").removeClass("with_attachments").css('paddingBottom', '');
},
bindServiceIcons: function(){
$(".service_icon").bind("click", function(evt){
$(this).toggleClass("dim");
Publisher.toggleServiceField($(this).attr('id'));
});
},
bindPublicIcon: function(){
$(".public_icon").bind("click", function(evt){
$(this).toggleClass("dim");
var public_field= $("#publisher #status_message_public");
(public_field.val() == 'false')?(public_field.val('true')):(public_field.val('false'));
});
},
toggleServiceField: function(service){
var hidden_field = $('#publisher [name="services[]"][value="'+service+'"]')
if(hidden_field.length > 0){
hidden_field.remove();
} else {
$("#publisher .content_creation form").append(
'<input id="services_" name="services[]" type="hidden" value="'+service+'">');
};
},
toggleAspectIds: function(aspectId) {
var hidden_field = $('#publisher [name="aspect_ids[]"][value="'+aspectId+'"]')
if(hidden_field.length > 0){
hidden_field.remove();
} else {
$("#publisher .content_creation form").append(
'<input id="aspect_ids_" name="aspect_ids[]" type="hidden" value="'+aspectId+'">');
};
},
bindAspectToggles: function() {
$('#publisher .aspect_badge').bind("click", function(){
var unremovedAspects = $(this).parent().children('.aspect_badge').length - $(this).parent().children(".aspect_badge.removed").length;
if(!$(this).hasClass('removed') && ( unremovedAspects == 1 )){
alert(Diaspora.widgets.i18n.t('publisher.at_least_one_aspect'))
}else{
Publisher.toggleAspectIds($(this).children('a').attr('data-guid'));
$(this).toggleClass("removed");
};
});
},
initialize: function() {
Publisher.cachedForm = false;
Publisher.cachedInput = false;
Publisher.cachedHiddenInput = false;
Publisher.cachedSubmit = false;
Publisher.bindServiceIcons();
Publisher.bindPublicIcon();
Publisher.bindAspectToggles();
if ($("#status_message_fake_text").val() == "") {
Publisher.close();
};
Publisher.autocompletion.initialize();
Publisher.hiddenInput().val(Publisher.input().val());
Publisher.input().keydown(Publisher.autocompletion.keyDownHandler);
Publisher.input().keyup(Publisher.autocompletion.keyUpHandler);
Publisher.form().find("textarea").bind("focus", function(evt) {
Publisher.open();
});
}
};
$(document).ready(function() {
Publisher.initialize();
});