Many JS improvements, moved a few things in view.js to stream.js, moved the clearForm plugin from view.js to rails.js (where we actually use it), refactored view.js and wrote specs

This commit is contained in:
OhaiBBQ 2010-12-04 11:54:59 +03:00
parent c5f2e8bb2d
commit ba23bd7a0a
5 changed files with 450 additions and 115 deletions

View file

@ -1,3 +1,23 @@
/* Clear form plugin - called using $("elem").clearForm(); */
$.fn.clearForm = function() {
return this.each(function() {
var type = this.type, tag = this.tagName.toLowerCase();
if (tag == 'form')
return $(':input',this).clearForm();
if (type == 'text' || type == 'password' || tag == 'textarea')
this.value = '';
else if (type == 'checkbox' || type == 'radio')
this.checked = false;
else if (tag == 'select')
this.selectedIndex = -1;
else if (this.name == 'photos[]')
this.value = '';
$(this).blur();
});
};
jQuery(function ($) {
var csrf_token = $('meta[name=csrf-token]').attr('content'),
csrf_param = $('meta[name=csrf-param]').attr('content');

View file

@ -15,6 +15,12 @@ var Stream = {
$(this).closest("form").children(".comment_box").attr("rows", 1);
});
$stream.delegate("textarea.comment_box", "keydown", function(e){
if (e.keyCode === 13) {
$(this).closest("form").submit();
}
});
$stream.delegate("textarea.comment_box", "focus", function(evt) {
var commentBox = $(this);
commentBox.attr("rows", 2)

View file

@ -2,127 +2,198 @@
* licensed under the Affero General Public License version 3 or later. See
* the COPYRIGHT file.
*/
var View = {
initialize: function() {
/* Buttons */
$("input[type='submit']").addClass("button");
$(document).ready(function(){
$('#debug_info').click(function() {
$('#debug_more').toggle('fast');
});
/* Tooltips */
this.tooltips.bindAll();
/* Animate flashes */
this.flashes.animate();
/* In field labels */
$("label").inFieldLabels();
$('#flash_notice, #flash_error, #flash_alert').animate({
/* Focus aspect name on fancybox */
$(this.addAspectButton.selector)
.click(this.addAspectButton.click);
/* Showing debug messages */
$(this.debug.selector)
.click(this.debug.click);
/* "Toggling" the search input */
$(this.search.selector)
.blur(this.search.blur)
.focus(this.search.focus);
/* Getting started animation */
$(this.gettingStarted.selector)
.live("click", this.gettingStarted.click);
/* Submitting the status message form when the user hits enter */
$(this.publisher.selector)
.keyup(this.publisher.keyup);
/* User menu */
$(this.userMenu.selector)
.click(this.userMenu.click);
/* Sending a request message */
$(this.newRequest.selector)
.live("submit", this.newRequest.submit);
/* Button fancyboxes */
$(this.fancyBoxButtons.selectors.join(", "))
.fancybox({
'titleShow': false,
'hideOnOverlayClick' : false
});
/* Webfinger form ajaxy loading */
$(this.webFingerForm.selector)
.submit(this.webFingerForm.submit);
$(document.body)
.click(this.userMenu.removeFocus);
},
addAspectButton: {
click: function() {
$("#aspect_name").focus();
},
selector: ".add_aspect_button"
},
fancyBoxButtons: {
selectors: [
".add_aspect_button",
".manage_aspect_contacts_button",
".invite_user_button",
".add_photo_button",
".remove_person_button",
".question_mark"
]
},
debug: {
click: function() {
$("#debug_more").toggle("fast");
},
selector: "#debug_info"
},
flashes: {
animate: function() {
var $this = $(View.flashes.selector);
$this.animate({
top: 0
}).delay(2000).animate({
top: -100
}, $(this).remove());
}, $this.remove())
},
selector: "#flash_notice, #flash_error, #flash_alert"
//buttons//////
$(".add_aspect_button," +
".manage_aspect_contacts_button," +
".add_photo_button," +
".remove_person_button," +
".question_mark").fancybox({ 'titleShow': false , 'hideOnOverlayClick' : false });
},
$("input[type='submit']").addClass("button");
// focus aspect name on fancybox
$(".add_aspect_button").click( function(){
$("#aspect_name").focus();
gettingStarted: {
click: function() {
var $this = $(this);
$this.animate({
left: parseInt($this.css("left"), 30) === 0 ? -$this.outerWidth() : 0
}, function() {
$this.css("left", "1000px");
});
},
selector: ".getting_started_box"
},
$("#q").focus(
function() {
$(this).addClass('active');
}
);
newRequest: {
submit: function() {
$(this).hide().parent().find(".message").removeClass("hidden");
},
selector: ".new_request"
},
$('.new_request').live("submit", function(){
var foo = $(this).parent();
$(this).hide();
foo.find('.message').removeClass('hidden');
});
$("#q").blur(
function() {
$(this).removeClass('active');
}
);
$("#publisher").find("textarea").keydown( function(e) {
publisher: {
keyup: function(e) {
if(e.keyCode === 13) {
$(this).closest("form").submit();
}
});
},
selector: "#publisher textarea"
},
$(".stream").delegate("textarea.comment_box", "keydown", function(e){
if (e.keyCode === 13) {
$(this).closest("form").submit();
search: {
blur: function() {
$(this).removeClass("active");
},
focus: function() {
$(this).addClass("active");
},
selector: "#q"
},
tooltips: {
addAspect: {
bind: function() {
$(".add_aspect_button", "#aspect_nav").tipsy({
gravity:"w"
});
}
});
},
$("#user_menu").click( function(){
avatars: {
bind: function() {
$("img.avatar").tipsy({
live: true
});
}
},
whatIsThis: {
bind: function() {
$(".what_is_this").tipsy({
live: true,
delayIn: 400
});
}
},
bindAll: function() {
for(var element in this) {
if(element !== "bindAll") {
this[element].bind();
}
};
}
},
userMenu: {
click: function() {
$(this).toggleClass("active");
});
},
removeFocus: function(evt) {
var $target = $(evt.target);
if(!$target.closest("#user_menu").length) {
$(View.userMenu.selector).removeClass("active");
}
},
selector: "#user_menu"
},
$('body').click( function(event){
var target = $(event.target);
if(!target.closest('#user_menu').length){
$("#user_menu").removeClass("active");
};
if(!target.closest('.reshare_pane').length){
$(".reshare_button").removeClass("active");
$(".reshare_box").hide();
};
});
$("img", "#left_pane").tipsy({live:true});
$(".add_aspect_button", "#aspect_nav").tipsy({gravity:'w'});
$(".person img", ".dropzone").tipsy({live:true});
$(".avatar", ".aspects").tipsy({live:true});
$(".what_is_this").tipsy({live:true,delayIn:400});
$('.webfinger_form').submit(function(evt){
form = $(evt.currentTarget);
form.siblings('#loader').show();
$('#request_result li:first').hide();
});
// hotkeys
$(window).bind('keyup', 'ctrl+f', function(){
$("#q").focus();
});
$(window).bind('keyup', 'ctrl+e', function(){
EditPane.toggle();
});
});//end document ready
//Called with $(selector).clearForm()
$.fn.clearForm = function() {
return this.each(function() {
var type = this.type, tag = this.tagName.toLowerCase();
if (tag == 'form')
return $(':input',this).clearForm();
if (type == 'text' || type == 'password' || tag == 'textarea')
this.value = '';
else if (type == 'checkbox' || type == 'radio')
this.checked = false;
else if (tag == 'select')
this.selectedIndex = -1;
else if (this.name == 'photos[]')
this.value = '';
$(this).blur();
});
webFingerForm: {
submit: function(evt) {
$(evt.currentTarget).siblings("#loader").show();
$("#request_result li:first").hide();
},
selector: ".webfinger_form"
}
};
$(".getting_started_box").live("click",function(evt){
$(this).animate({
left: parseInt($(this).css('left'),30) == 0 ?
-$(this).outerWidth() :
0
},function(evt){ $(this).css('left', '1000px')});
$(function() {
/* Make sure this refers to View, not the document */
View.initialize.apply(View);
});

View file

@ -14,14 +14,16 @@ src_files:
- public/javascripts/vendor/jquery144.js
- public/javascripts/vendor/jquery-ui-1.8.6.custom.min.js
- public/javascripts/vendor/jquery.tipsy.js
- public/javascripts/validation.js
- public/javascripts/vendor/jquery.infieldlabel.js
- public/javascripts/vendor/fancybox/jquery.fancybox-1.3.1.pack.js
- public/javascripts/diaspora.js
- public/javascripts/mobile.js
- public/javascripts/aspect-edit.js
- public/javascripts/aspect-contacts.js
- public/javascripts/web-socket-receiver.js
- public/javascripts/view.js
- public/javascripts/stream.js
- public/javascripts/validation.js
# stylesheets
#
# Return an array of stylesheet filepaths relative to src_dir to include before jasmine specs.

View file

@ -0,0 +1,236 @@
describe("View", function() {
it("is the object that helps the UI", function() {
expect(typeof View === "object").toBeTruthy();
});
describe("initialize", function() {
it("is called on DOM ready", function() {
spyOn(View, "initialize");
$(View.initialize);
expect(View.initialize).toHaveBeenCalled();
});
});
describe("fancyBoxButtons", function() {
describe("selectors", function() {
it("is an array of all the selectors that will have fancybox attached", function() {
expect(typeof View.fancyBoxButtons.selectors === "object").toBeTruthy();
expect($.isArray(View.fancyBoxButtons.selectors)).toBeTruthy();
});
});
});
describe("debug", function() {
describe("click", function() {
beforeEach(function() {
$("#jasmine_content").html(
'<div id="debug_info">' +
'<h5>DEBUG INFO</h5>' +
'<div id="debug_more" style="display: none;">' +
'DEBUG INFO' +
'</div>' +
'</div>'
);
});
it("is called when the user clicks an element matching the selector", function() {
spyOn(View.debug, "click");
View.initialize();
$(View.debug.selector).click();
expect(View.debug.click).toHaveBeenCalled();
setTimeout(function() {
expect($(View.debug.selector).css("display")).toEqual("block");
}, 500);
});
});
});
describe("flashes", function() {
describe("animate", function() {
beforeEach(function() {
$("#jasmine_content").html(
'<div id="flash_notice">' +
'flash! flash! flash!' +
'</div>'
);
});
it("is called when the DOM is ready", function() {
spyOn(View.flashes, "animate").andCallThrough();
View.initialize();
expect(View.flashes.animate).toHaveBeenCalled();
});
});
});
describe("newRequest", function() {
beforeEach(function() {
$("#jasmine_content").html(
'<div id="user@joindiaspora.com">' +
'<form accept-charset="UTF-8" action="/requests" class="new_request" data-remote="true" id="new_request" method="post">' +
'<div style="margin:0;padding:0;display:inline">' +
'<input id="request_to" name="request[to]" type="hidden" value="user@joindiaspora.com">' +
'<input data-disable-with="Sending" id="request_submit" name="commit" type="submit" value="add contact" class="button">' +
'</form>' +
'<div class="message hidden">' +
'<i>sent!</i>' +
'</div>' +
'</div>'
);
});
describe("submit", function() {
it("is called when the user submits the form", function() {
spyOn(View.newRequest, "submit").andCallThrough();
View.initialize();
$(View.newRequest.selector).submit(function(evt) { evt.preventDefault(); });
$(View.newRequest.selector).trigger("submit");
expect(View.newRequest.submit).toHaveBeenCalled();
expect($(View.newRequest.selector + " .message").css("display")).toEqual("block");
});
});
});
describe("publisher", function() {
beforeEach(function() {
$("#jasmine_content").html(
'<div id="publisher">' +
'<form action="/status_messages" class="new_status_message" id="new_status_message" method="post">' +
'<textarea id="status_message_message" name="status_message[message]"></textarea>' +
'</form>' +
'</div>'
);
});
describe("keyup", function() {
it("is called when the user types", function() {
spyOn(View.publisher, "keyup");
View.initialize();
$(View.publisher.selector).trigger("keyup");
expect(View.publisher.keyup).toHaveBeenCalled();
});
it("submits the form if the user hits enter while the textarea is focused", function() {
spyOn($.fn, "submit");
View.initialize();
$(View.publisher.selector).focus();
var event = $.Event("keyup");
event.keyCode = 13;
$(View.publisher.selector).trigger(event);
expect($.fn.submit).toHaveBeenCalled();
});
});
});
describe("search", function() {
beforeEach(function() {
$("#jasmine_content").html(
'<input id="q" name="q" placeholder="Search" results="5" type="search" class="">'
);
});
describe("focus", function() {
it("adds the class 'active' when the user focuses the text field", function() {
View.initialize();
$(View.search.selector).focus();
expect($(View.search.selector)).toHaveClass("active");
});
});
describe("blur", function() {
it("removes the class 'active' when the user blurs the text field", function() {
View.initialize();
$(View.search.selector).focus().blur();
expect($(View.search.selector)).not.toHaveClass("active");
});
});
});
describe("tooltips", function() {
describe("bindAll", function() {
//Someone shorten this plz <3
it("enumerates through the tooltips object, called the method 'bind' on any sibling that is not the bindAll method", function() {
spyOn($, "noop");
View.initialize();
View.tooltips.myToolTip = { bind: $.noop };
View.tooltips.bindAll();
expect($.noop).toHaveBeenCalled();
});
});
});
describe("userMenu", function() {
beforeEach(function() {
$("#jasmine_content").html(
'<ul id="user_menu">' +
'<div class="right">' +
'.' +
'</div>' +
'<div class="avatar">' +
'<img alt="Jasmine Specson" class="avatar" title="Jasmine Specson">' +
'</div>' +
'<a href="#">Jasmine Specson</a>' +
'</ul>'
);
});
describe("click", function() {
it("adds the class 'active' when the user clicks the ul", function() {
View.initialize();
$(View.userMenu.selector).click();
expect($(View.userMenu.selector)).toHaveClass("active");
});
});
describe("removeFocus", function() {
it("removes the class 'active' if the user clicks anywhere that isnt the userMenu", function() {
View.initialize();
$(View.userMenu.selector).click();
expect($(View.userMenu.selector)).toHaveClass("active");
var event = $.Event("click");
event.target = document.body;
$(document.body).trigger(event);
expect($(View.userMenu.selector)).not.toHaveClass("active");
});
});
});
describe("webFingerForm", function() {
beforeEach(function() {
$("#jasmine_content").html(
'<div class="span-7 last">' +
'<h4>' +
'Add a new contact' +
'</h4>' +
'<form accept-charset="UTF-8" action="/people/by_handle" class="webfinger_form" data-remote="true" method="post">' +
'<input name="diaspora_handle" placeholder="diaspora@handle.org" results="5" type="search" value="">' +
'<input name="commit" type="submit" value="Find by Diaspora handle" class="button">' +
'</form>' +
'<div class="hidden" id="loader">' +
'<img alt="Ajax-loader" src="/images/ajax-loader.gif?1290478032">' +
'</div>' +
'<ul id="request_result">' +
'<li class="error hidden">' +
'<div id="message">' +
'<a href="/users/invitation/new">Know their email address? You should invite them</a>' +
'</div>' +
'</li>' +
'</ul>' +
'</div>'
);
// Prevent the form from being submitted
$(View.webFingerForm.selector).submit(function(evt) { evt.preventDefault(); });
});
describe("submit", function() {
it("shows the ajax loader after the user submits the form", function() {
View.initialize();
$(View.webFingerForm.selector).submit();
expect($(View.webFingerForm.selector).siblings("#loader").css("display")).toEqual("block");
});
it("hides the first list item in the result ul after the user submits the form", function() {
View.initialize();
$(View.webFingerForm.selector).submit();
expect($("#request_result li:first").css("display")).toEqual("none");
});
});
});
});