From 3d8f971ca9d5fb3e5634e10b40fb01b4d0bd4c6e Mon Sep 17 00:00:00 2001 From: Dan Hansen Date: Thu, 27 Oct 2011 22:07:55 -0500 Subject: [PATCH] refactor aspects dropdown, (wip, still need to backfill specs) --- config/assets.yml | 1 - config/locales/javascript/javascript.en.yml | 4 +- public/javascripts/aspects-dropdown.js | 61 -------- public/javascripts/contact-edit.js | 89 ------------ public/javascripts/pages/contacts-index.js | 4 + public/javascripts/pages/people-show.js | 1 + public/javascripts/publisher.js | 17 +-- .../javascripts/widgets/aspects-dropdown.js | 133 ++++++++++++++++++ public/javascripts/widgets/hovercard.js | 3 +- spec/javascripts/helpers/SpecHelper.js | 6 - .../widgets/aspects-dropdown-spec.js | 116 +++++++++++++++ 11 files changed, 263 insertions(+), 172 deletions(-) delete mode 100644 public/javascripts/contact-edit.js create mode 100644 public/javascripts/widgets/aspects-dropdown.js create mode 100644 spec/javascripts/widgets/aspects-dropdown-spec.js diff --git a/config/assets.yml b/config/assets.yml index 7c3a66341..3f6252a96 100644 --- a/config/assets.yml +++ b/config/assets.yml @@ -35,7 +35,6 @@ javascripts: - public/javascripts/view.js - public/javascripts/stream.js - public/javascripts/content-updater.js - - public/javascripts/aspects-dropdown.js - public/javascripts/contact-edit.js - public/javascripts/contact-list.js - public/javascripts/aspect-sorting.js diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml index 332e3b75b..8bd13bb1d 100644 --- a/config/locales/javascript/javascript.en.yml +++ b/config/locales/javascript/javascript.en.yml @@ -67,4 +67,6 @@ en: photo_uploader: looking_good: "OMG, you look awesome!" tags: - wasnt_that_interesting: "OK, I suppose #{{tagName}} wasn't all that interesting..." + wasnt_that_interesting: "OK, I suppose #{{tagName}} wasn't all that interesting..." + inviter: + sending: "sending, please wait..." \ No newline at end of file diff --git a/public/javascripts/aspects-dropdown.js b/public/javascripts/aspects-dropdown.js index 61f035d17..e69de29bb 100644 --- a/public/javascripts/aspects-dropdown.js +++ b/public/javascripts/aspects-dropdown.js @@ -1,61 +0,0 @@ -// Copyright (c) 2010-2011, Diaspora Inc. This file is -// licensed under the Affero General Public License version 3 or later. See -// the COPYRIGHT file. - -var AspectsDropdown = { - updateNumber: function(dropdown, personId, number, inAspectClass){ - var button = dropdown.parents(".dropdown").children('.button.toggle'), - selectedAspects = dropdown.children(".selected").length, - allAspects = dropdown.children().length, - replacement; - - if (number == 0) { - button.removeClass(inAspectClass); - if( dropdown.closest('#publisher').length ) { - replacement = Diaspora.I18n.t("aspect_dropdown.select_aspects"); - } else { - replacement = Diaspora.I18n.t("aspect_dropdown.add_to_aspect"); - /* flash message prompt */ - var message = Diaspora.I18n.t("aspect_dropdown.stopped_sharing_with", {name: dropdown.data('person-short-name')}); - Diaspora.page.flashMessages.render({success: true, notice: message}); - } - }else if (selectedAspects == allAspects) { - replacement = Diaspora.I18n.t('aspect_dropdown.all_aspects'); - }else if (number == 1) { - button.addClass(inAspectClass); - replacement = dropdown.find(".selected").first().text(); - /* flash message prompt */ - if( dropdown.closest('#publisher').length == 0 ) { - var message = Diaspora.I18n.t("aspect_dropdown.started_sharing_with", {name: dropdown.data('person-short-name')}); - Diaspora.page.flashMessages.render({success: true, notice: message}); - } - }else { - replacement = Diaspora.I18n.t('aspect_dropdown.toggle', { count: number.toString()}) - } - - button.text(replacement + ' ▼'); - }, - - toggleCheckbox: function(check) { - if(!check.hasClass('radio')){ - var selectedAspects = check.closest(".dropdown").find("li.radio"); - AspectsDropdown.uncheckGroup(selectedAspects); - } - - check.toggleClass('selected'); - }, - - toggleRadio: function(check) { - var selectedAspects = check.closest(".dropdown").find("li"); - - AspectsDropdown.uncheckGroup(selectedAspects); - AspectsDropdown.toggleCheckbox(check); - }, - - uncheckGroup: function(elements){ - $.each(elements, function(index, value) { - $(value).removeClass('selected'); - }); - } -}; - diff --git a/public/javascripts/contact-edit.js b/public/javascripts/contact-edit.js deleted file mode 100644 index 4e55200df..000000000 --- a/public/javascripts/contact-edit.js +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2010-2011, Diaspora Inc. This file is -// licensed under the Affero General Public License version 3 or later. See -// the COPYRIGHT file. - -var ContactEdit = { - init: function(){ - $.extend(ContactEdit, AspectsDropdown); - $('.dropdown.aspect_membership .dropdown_list > li, .dropdown.inviter .dropdown_list > li').live('click', function(evt){ - - ContactEdit.processClick($(this), evt); - }); - }, - - updateNumber: function(dropdown, personId, number){ - var button = dropdown.parents(".dropdown").children('.button.toggle'), - replacement; - - if (number == 0) { - button.removeClass("in_aspects"); - replacement = Diaspora.I18n.t("aspect_dropdown.toggle.zero"); - }else if (number == 1) { - button.addClass("in_aspects"); - replacement = dropdown.find(".selected").first().text(); - }else if (number < 3) { - replacement = Diaspora.I18n.t('aspect_dropdown.toggle.few', { count: number.toString()}) - }else if (number > 3) { - replacement = Diaspora.I18n.t('aspect_dropdown.toggle.many', { count: number.toString()}) - }else { - //the above one are a tautology, but I want to have them here once for once we figure out a neat way i18n them - replacement = Diaspora.I18n.t('aspect_dropdown.toggle.other', { count: number.toString()}) - ContactEdit.toggleAspectMembership(li, evt); - } - }, - - inviteFriend: function(li, evt) { - $.post('/services/inviter/facebook.json', { - "aspect_id" : li.data("aspect_id"), - "uid" : li.parent().data("service_uid") - }, function(data){ - ContactEdit.processSuccess(li, evt, data); - }); - }, - - processSuccess: function(element, evt, data) { - element.removeClass('loading') - if (data.url != undefined) { - window.location = data.url; - } else { - element.toggleClass("selected"); - Diaspora.widgets.flashes.render({'success':true, 'notice':data.message}); - } - }, - - processClick: function(li, evt){ - var dropdown = li.closest('.dropdown'); - li.addClass('loading'); - if (dropdown.hasClass('inviter')) { - ContactEdit.inviteFriend(li, evt); - dropdown.html('sending, please wait...'); - } - else { - ContactEdit.toggleAspectMembership(li, evt); - } - }, - - toggleAspectMembership: function(li, evt) { - var button = li.find('.button'); - if(button.hasClass('disabled') || li.hasClass('newItem')){ return; } - - var selected = li.hasClass("selected"), - routedId = selected ? "/42" : ""; - - $.post("/aspect_memberships" + routedId + ".json", { - "aspect_id": li.data("aspect_id"), - "person_id": li.parent().data("person_id"), - "_method": (selected) ? "DELETE" : "POST" - }, function(aspectMembership) { - li.removeClass("loading"); - ContactEdit.toggleCheckbox(li); - ContactEdit.updateNumber(li.closest(".dropdown_list"), li.parent().data("person_id"), aspectMembership.aspect_ids.length, 'in_aspects'); - - Diaspora.page.publish("aspectDropdown/updated", [li.parent().data("person_id"), li.parents(".dropdown").parent(".right").html()]); - }); - } -}; - -$(document).ready(function(){ - ContactEdit.init(); -}); diff --git a/public/javascripts/pages/contacts-index.js b/public/javascripts/pages/contacts-index.js index e036172a3..35a60cf32 100644 --- a/public/javascripts/pages/contacts-index.js +++ b/public/javascripts/pages/contacts-index.js @@ -4,6 +4,10 @@ Diaspora.Pages.ContactsIndex = function() { this.subscribe("page/ready", function(evt, document) { self.infiniteScroll = self.instantiate("InfiniteScroll"); + $(".aspect_membership.dropdown").each(function() { + self.instantiate("AspectsDropdown", $(this)); + }); + $('.conversation_button').twipsy({position: 'below'}); }); }; diff --git a/public/javascripts/pages/people-show.js b/public/javascripts/pages/people-show.js index 84c0173b8..b05521207 100644 --- a/public/javascripts/pages/people-show.js +++ b/public/javascripts/pages/people-show.js @@ -2,6 +2,7 @@ Diaspora.Pages.PeopleShow = function() { var self = this; this.subscribe("page/ready", function(evt, document) { + self.aspectsDropdown = self.instantiate("AspectsDropdown", document.find(".aspect_membership.dropdown")); self.stream = self.instantiate("Stream", document.find("#main_stream")); self.infiniteScroll = self.instantiate("InfiniteScroll"); }); diff --git a/public/javascripts/publisher.js b/public/javascripts/publisher.js index abad86f9a..9278337c3 100644 --- a/public/javascripts/publisher.js +++ b/public/javascripts/publisher.js @@ -379,21 +379,12 @@ var Publisher = { }, bindAspectToggles: function() { - $('#publisher .dropdown .dropdown_list li').bind("click", function(evt){ - var li = $(this), - button = li.parent('.dropdown').find('.button'); - - if(li.hasClass('radio')){ - AspectsDropdown.toggleRadio(li); - } else { - AspectsDropdown.toggleCheckbox(li); - } - - AspectsDropdown.updateNumber(li.closest(".dropdown_list"), null, li.parent().find('li.selected').length, ''); - - Publisher.toggleAspectIds(li); + Publisher.aspectsDropdown = Diaspora.BaseWidget.instantiate("AspectsDropdown", $("#publisher .dropdown")); + Publisher.aspectsDropdown.aspectSelectors.click(function() { + Publisher.toggleAspectIds($(this)); }); }, + beforeSubmit: function(){ if($("#publisher .content_creation form #aspect_ids_").length == 0){ alert(Diaspora.I18n.t('publisher.at_least_one_aspect')); diff --git a/public/javascripts/widgets/aspects-dropdown.js b/public/javascripts/widgets/aspects-dropdown.js new file mode 100644 index 000000000..2c9d776e2 --- /dev/null +++ b/public/javascripts/widgets/aspects-dropdown.js @@ -0,0 +1,133 @@ +/* Copyright (c) 2010-2011, Diaspora Inc. This file is + * licensed under the Affero General Public License version 3 or later. See + * the COPYRIGHT file. + */ + +(function() { + var AspectsDropdown = function() { + var self = this; + + this.subscribe("widget/ready", function(evt, dropdown) { + $.extend(self, { + aspectSelectors: dropdown.find("li.aspect_selector"), + radioSelectors: dropdown.find("li.radio"), + dropdown: dropdown, + dropdownButton: dropdown.children(".button.toggle"), + dropdownList: dropdown.find("ul.dropdown_list"), + inviterDropdown: dropdown.hasClass("inviter"), + publisherDropdown: !!dropdown.closest("#publisher").length + }); + + self.personId = self.dropdownList.data("person_id"); + + self.aspectSelectors.click(self.aspectClicked); + self.radioSelectors.click(self.radioClicked); + }); + + this.aspectClicked = function(evt) { + var aspectListItem = $(this); + if (self.inviterDropdown) { + self.inviteFriend(aspectListItem); + } + else if(self.publisherDropdown) { + self.toggleAspectSelection(aspectListItem); + } + else { + self.toggleAspectMembership(aspectListItem); + } + }; + + this.radioClicked = function() { + self.aspectSelectors + .add(self.radioSelectors) + .not(this) + .removeClass("selected"); + + $(this).toggleClass("selected") + }; + + this.toggleAspectSelection = function(aspect) { + self.radioSelectors.removeClass("selected"); + + aspect.toggleClass("selected"); + }; + + this.inviteFriend = function(aspectListItem) { + self.dropdown.html(Diaspora.I18n.t("inviter.sending")); + $.post('/services/inviter/facebook.json', { + "aspect_id" : aspectListItem.data("aspect_id"), + "uid" : self.dropdownList.data("service_uid") + }, function(data) { + aspectListItem.removeClass("loading"); + if (typeof data.url !== "undefined") { + window.location = data.url; + } else { + aspectListItem.toggleClass("selected"); + + Diaspora.page.flashMessages.render({ + success: true, + notice: data.message + }); + } + }); + }; + + this.toggleAspectMembership = function(aspectListItem) { + var aspectId = aspectListItem.data("aspect_id"), + button = aspectListItem.find(".button"); + + if(button.hasClass("disabled") || aspectListItem.hasClass("newItem")) { return; } + + var selected = aspectListItem.hasClass("selected"), + routedId = selected ? "/42" : ""; + + aspectListItem.addClass("loading"); + + $.post("/aspect_memberships" + routedId + ".json", { + "aspect_id": aspectId, + "person_id": self.personId, + "_method": (selected) ? "DELETE" : "POST" + }, function() { + aspectListItem.removeClass("loading") + .toggleClass("selected"); + + self.updateDropdownText(); + + self.globalPublish("aspectDropdown/updated", [self.personId, self.dropdown.parent().html()]); + }); + }; + + this.updateDropdownText = function() { + var selectedAspects = self.dropdownList.children(".selected").length, + allAspects = self.dropdownList.children().length, + replacement; + + if (selectedAspects == 0) { + self.dropdownButton.removeClass("in_aspects"); + + if(self.dropdown.closest("#publisher").length) { + replacement = Diaspora.I18n.t("aspect_dropdown.select_aspects"); + } else { + replacement = Diaspora.I18n.t("aspect_dropdown.add_to_aspect"); + } + } + else if (selectedAspects === allAspects) { + replacement = Diaspora.I18n.t("aspect_dropdown.all_aspects"); + } + else if (selectedAspects === 1) { + self.dropdownButton.addClass("in_aspects"); + + replacement = self.dropdown.find(".selected:first").text(); + } + else if (selectedAspects > 1) { + replacement = Diaspora.I18n.t("aspect_dropdown.toggle", { + count: selectedAspects + }); + } + + self.dropdownButton.text(replacement + " ▼"); + } + }; + + Diaspora.Widgets.AspectsDropdown = AspectsDropdown; +})(); \ No newline at end of file diff --git a/public/javascripts/widgets/hovercard.js b/public/javascripts/widgets/hovercard.js index 028fea325..c8ad0e4fd 100644 --- a/public/javascripts/widgets/hovercard.js +++ b/public/javascripts/widgets/hovercard.js @@ -24,7 +24,7 @@ $(document.body).delegate("a.hovercardable:not(.self)", "hover", self.handleHoverEvent); self.hoverCard.tip.hover(self.hoverCardHover, self.clearTimeout); - self.subscribe("aspectDropdown/updated aspectDropdown/blurred", function(evt, personId, dropdownHtml) { + self.globalSubscribe("aspectDropdown/updated", function(evt, personId, dropdownHtml) { self.dropdownCache.cache["/people/" + personId + "/aspect_membership_button"] = $(dropdownHtml).removeClass("active").get(0).outerHTML; }); }); @@ -79,6 +79,7 @@ self.dropdownCache.get(self.target.attr("data-hovercard") + "/aspect_membership_button", function(dropdown) { self.hoverCard.dropdownContainer.html(dropdown); + self.hoverCard.dropdownWidget = self.instantiate("AspectsDropdown", self.hoverCard.dropdownContainer.children()); self.hoverCard.tip.fadeIn(140); }); }; diff --git a/spec/javascripts/helpers/SpecHelper.js b/spec/javascripts/helpers/SpecHelper.js index ccb456878..b858686ec 100644 --- a/spec/javascripts/helpers/SpecHelper.js +++ b/spec/javascripts/helpers/SpecHelper.js @@ -22,12 +22,6 @@ beforeEach(function() { self.directionDetector = self.instantiate("DirectionDetector"); }); }; - - var Page = Diaspora.Pages["TestPage"]; - $.extend(Page.prototype, Diaspora.EventBroker.extend(Diaspora.BaseWidget)); - - Diaspora.page = new Page(); - Diaspora.page.publish("page/ready", [$(document.body)]) }); afterEach(function() { diff --git a/spec/javascripts/widgets/aspects-dropdown-spec.js b/spec/javascripts/widgets/aspects-dropdown-spec.js new file mode 100644 index 000000000..cceab3a18 --- /dev/null +++ b/spec/javascripts/widgets/aspects-dropdown-spec.js @@ -0,0 +1,116 @@ +describe("Diaspora.Widgets.AspectsDropdown", function() { + var aspectsDropdownWidget, + aspectsDropdown; + + describe("when the dropdown is a publisher dropdown", function() { + beforeEach(function() { + spec.loadFixture("aspects_index"); + + Diaspora.Page = "TestPage"; + Diaspora.instantiatePage(); + + aspectsDropdown = $("#publisher .dropdown"); + aspectsDropdownWidget = Diaspora.BaseWidget.instantiate("AspectsDropdown", aspectsDropdown); + }); + + describe("clicking a radio button", function() { + describe("integration", function() { + it("calls AspectsDropdown#radioClicked", function() { + aspectsDropdownWidget = new Diaspora.Widgets.AspectsDropdown(); + + spyOn(aspectsDropdownWidget, "radioClicked"); + + aspectsDropdownWidget.publish("widget/ready", [aspectsDropdown]); + + aspectsDropdownWidget.radioSelectors.first().click(); + + expect(aspectsDropdownWidget.radioClicked).toHaveBeenCalled(); + }) + }); + + it("clears the selected aspects", function() { + var aspectSelectors = aspectsDropdown.find(".aspect_selector").click(); + + expect(aspectsDropdown).toContain("li.aspect_selector.selected"); + + aspectsDropdown.find(".radio:first").click(); + + expect(aspectsDropdown).not.toContain("li.aspect_selector.selected"); + }); + + it("clears selected radio buttons", function() { + aspectsDropdown.find(".selected").removeClass("selected"); + + var firstRadioSelector = aspectsDropdown.find(".radio:first"), + lastRadioSelector = aspectsDropdown.find(".radio:last"); + + expect(firstRadioSelector).not.toHaveClass("selected"); + expect(lastRadioSelector).not.toHaveClass("selected"); + + firstRadioSelector.click(); + + expect(firstRadioSelector).toHaveClass("selected"); + + lastRadioSelector.click(); + + expect(firstRadioSelector).not.toHaveClass("selected"); + expect(lastRadioSelector).toHaveClass("selected"); + }); + + it("toggles the radio selector", function() { + var radioSelector = aspectsDropdown.find(".radio:first"); + + expect(radioSelector).not.toHaveClass("selected"); + + radioSelector.click(); + + expect(radioSelector).toHaveClass("selected"); + + radioSelector.click(); + + expect(radioSelector).not.toHaveClass("selected"); + }); + }); + + describe("clicking an aspect", function() { + describe("integration", function() { + it("calls through to AspectsDropdown#toggleAspectSelection", function() { + aspectsDropdownWidget = new Diaspora.Widgets.AspectsDropdown(); + + spyOn(aspectsDropdownWidget, "toggleAspectSelection"); + + aspectsDropdownWidget.publish("widget/ready", [aspectsDropdown]); + + aspectsDropdownWidget.aspectSelectors.first().click(); + + expect(aspectsDropdownWidget.toggleAspectSelection).toHaveBeenCalled(); + }); + }); + + it("deselects the radio buttons", function() { + var aspectSelector = aspectsDropdownWidget.aspectSelectors.first(), + radioSelector = aspectsDropdown.find(".radio:last"); + + expect(radioSelector).toHaveClass("selected"); + + aspectSelector.click(); + + expect(radioSelector).not.toHaveClass("selected"); + }); + + it("toggles the aspect selector", function() { + var aspectSelector = aspectsDropdownWidget.aspectSelectors.first(); + + expect(aspectSelector).not.toHaveClass("selected"); + + aspectSelector.click(); + + expect(aspectSelector).toHaveClass("selected"); + + aspectSelector.click(); + + expect(aspectSelector).not.toHaveClass("selected"); + }); + }); + }); +}); \ No newline at end of file